home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / bin / DXUtils / AppWizard / DXAppwiz.awx / TEMPLATE / GDI_WIN.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-25  |  84.5 KB  |  2,340 lines

  1. //-----------------------------------------------------------------------------
  2. // File: $$root$$.cpp
  3. //
  4. // Desc: DirectX window application created by the DirectX AppWizard
  5. //-----------------------------------------------------------------------------
  6. #define STRICT
  7. $$IF(DINPUT)
  8. #define DIRECTINPUT_VERSION 0x0800
  9. $$ENDIF
  10. #include <windows.h>
  11. #include <basetsd.h>
  12. #include <math.h>
  13. #include <stdio.h>
  14. #include <DXErr8.h>
  15. #include <tchar.h>
  16. $$IF(DINPUT)
  17. #include <dinput.h>
  18. $$ENDIF
  19. $$IF(DPLAY)
  20. #include <dplay8.h>
  21. #include <dplobby8.h>
  22. $$ENDIF
  23. $$IF(ACTIONMAPPER)
  24. #include "DIUtil.h"
  25. $$ENDIF
  26. $$IF(DMUSIC)
  27. #include "DMUtil.h"
  28. $$ENDIF
  29. $$IF(DSOUND)
  30. #include "DSUtil.h"
  31. $$ENDIF
  32. $$IF(DPLAY)
  33. #include "NetConnect.h"
  34. $$ENDIF
  35. $$IF(DPLAYVOICE)
  36. #include "NetVoice.h"
  37. $$ENDIF
  38. #include "DXUtil.h"
  39. #include "resource.h"
  40. #include "$$root$$.h"
  41.  
  42.  
  43.  
  44. $$IF(ACTIONMAPPER|DPLAY)
  45. //-----------------------------------------------------------------------------
  46. // Defines, and constants
  47. //-----------------------------------------------------------------------------
  48. // This GUID must be unique for every game, and the same for 
  49. // every instance of this app.  // $$GUIDMSG$$
  50. $$IF(DPLAY)
  51. // The GUID allows DirectPlay to find other instances of the same game on
  52. // the network.  
  53. $$ENDIF // end DPLAY
  54. $$IF(ACTIONMAPPER)
  55. // The GUID allows DirectInput to remember input settings
  56. $$ENDIF // end ACTIONMAPPER
  57. GUID g_guidApp = $$GUIDSTRUCT$$;
  58.  
  59.  
  60. $$ENDIF // end (ACTIONMAPPER|DPLAY)
  61. $$IF(ACTIONMAPPER)
  62.  
  63.  
  64.  
  65.  
  66. // Input semantics used by this app
  67. enum INPUT_SEMANTICS
  68. {
  69.     // Gameplay semantics
  70.     // TODO: change as needed
  71.     INPUT_ROTATE_AXIS_LR=1, INPUT_ROTATE_AXIS_UD,       
  72.     INPUT_ROTATE_LEFT,      INPUT_ROTATE_RIGHT,    
  73.     INPUT_ROTATE_UP,        INPUT_ROTATE_DOWN,
  74.     INPUT_CONFIG_INPUT,     
  75. $$IF(DPLAYVOICE)
  76.     INPUT_CONFIG_VOICE,     
  77. $$ENDIF
  78. $$IF(DMUSIC || DSOUND)
  79.     INPUT_PLAY_SOUND,       
  80. $$ENDIF
  81. };
  82.  
  83. // Actions used by this app
  84. DIACTION g_rgGameAction[] =
  85. {
  86.     // TODO: change as needed.  Be sure to delete user map files 
  87.     // (C:\Program Files\DirectX\DirectInput\User Maps\*.ini)
  88.     // after changing this, otherwise settings won't reset and will be read 
  89.     // from the out of date ini files 
  90.  
  91.     // Device input (joystick, etc.) that is pre-defined by DInput, according
  92.     // to genre type. The genre for this app is space simulators.
  93.     { INPUT_ROTATE_AXIS_LR,  DIAXIS_3DCONTROL_LATERAL,      0, TEXT("Rotate left/right"), },
  94.     { INPUT_ROTATE_AXIS_UD,  DIAXIS_3DCONTROL_MOVE,         0, TEXT("Rotate up/down"), },
  95. $$IF(DMUSIC || DSOUND)
  96.     { INPUT_PLAY_SOUND,      DIBUTTON_3DCONTROL_SPECIAL,    0, TEXT("Play sound"), },
  97. $$ENDIF
  98.  
  99.     // Keyboard input mappings
  100.     { INPUT_ROTATE_LEFT,     DIKEYBOARD_LEFT,               0, TEXT("Rotate left"), },
  101.     { INPUT_ROTATE_RIGHT,    DIKEYBOARD_RIGHT,              0, TEXT("Rotate right"), },
  102.     { INPUT_ROTATE_UP,       DIKEYBOARD_UP,                 0, TEXT("Rotate up"), },
  103.     { INPUT_ROTATE_DOWN,     DIKEYBOARD_DOWN,               0, TEXT("Rotate down"), },
  104. $$IF(DMUSIC || DSOUND)
  105.     { INPUT_PLAY_SOUND,      DIKEYBOARD_F5,                 0, TEXT("Play sound"), },
  106. $$ENDIF
  107.     { INPUT_CONFIG_INPUT,    DIKEYBOARD_F3,                 DIA_APPFIXED, TEXT("Configure Input"), },    
  108. $$IF(DPLAYVOICE)
  109.     { INPUT_CONFIG_VOICE,    DIKEYBOARD_F4,                 DIA_APPFIXED, TEXT("Configure Voice"), },    
  110. $$ENDIF
  111. };
  112.  
  113. #define NUMBER_OF_GAMEACTIONS    (sizeof(g_rgGameAction)/sizeof(DIACTION))
  114.  
  115.  
  116.  
  117.  
  118. $$ENDIF
  119. //-----------------------------------------------------------------------------
  120. // Function prototypes 
  121. //-----------------------------------------------------------------------------
  122. LRESULT CALLBACK StaticMsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
  123.  
  124.  
  125.  
  126.  
  127. //-----------------------------------------------------------------------------
  128. // Global access to the app (needed for the global WndProc())
  129. //-----------------------------------------------------------------------------
  130. CMyApplication*    g_pApp  = NULL;
  131. HINSTANCE          g_hInst = NULL;
  132.  
  133.  
  134.  
  135.  
  136. //-----------------------------------------------------------------------------
  137. // Name: WinMain()
  138. // Desc: Application entry point
  139. //-----------------------------------------------------------------------------
  140. INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow )
  141. {
  142.     CMyApplication app;
  143.  
  144.     g_hInst = hInstance;
  145.  
  146.     if( FAILED( app.Create( hInstance ) ) )
  147.         return 0;
  148.  
  149.     return app.Run();
  150. }
  151.  
  152.  
  153.  
  154.  
  155. //-----------------------------------------------------------------------------
  156. // Name: CMyApplication()
  157. // Desc: Constructor
  158. //-----------------------------------------------------------------------------
  159. CMyApplication::CMyApplication()
  160. {
  161.     g_pApp                      = this;
  162.  
  163.     m_hWnd                      = NULL;
  164.     m_strWindowTitle            = TEXT( "$$root$$" );
  165.     m_dwCreationWidth           = 500;
  166.     m_dwCreationHeight          = 375;
  167.     m_bLoadingApp               = TRUE;
  168.  
  169. $$IF(KEYBOARD)
  170.     m_pDI                       = NULL;
  171.     m_pKeyboard                 = NULL;
  172. $$ENDIF
  173. $$IF(ACTIONMAPPER)
  174.     m_pInputDeviceManager       = NULL;
  175. $$ENDIF
  176. $$IF(DMUSIC || DSOUND)
  177. $$IF(DMUSIC)
  178.     m_pMusicManager             = NULL;
  179.     m_pBounceSound              = NULL;
  180. $$ELSE
  181.     m_pSoundManager             = NULL;
  182.     m_pBounceSound              = NULL;
  183. $$ENDIF
  184. $$ENDIF
  185.  
  186.     ZeroMemory( &m_UserInput, sizeof(m_UserInput) );
  187.     m_fWorldRotX                = 0.0f;
  188.     m_fWorldRotY                = 0.0f;
  189. $$IF(DPLAY)
  190.  
  191.     m_pDP                       = NULL;    
  192.     m_pNetConnectWizard         = NULL;    
  193.     m_pLobbiedApp               = NULL;    
  194.     m_bWasLobbyLaunched         = FALSE;   
  195.     m_dpnidLocalPlayer          = 0;       
  196.     m_lNumberOfActivePlayers    = 0;       
  197.     m_pLocalPlayerInfo          = NULL;
  198.     m_hrNet                     = S_OK;
  199.     m_fWorldSyncTimer           = 0.0f;
  200.     m_bHostPausing              = FALSE;
  201.  
  202.     ZeroMemory( &m_PlayInfoList, sizeof(APP_PLAYER_INFO) );
  203.     m_PlayInfoList.pNext = &m_PlayInfoList;
  204.     m_PlayInfoList.pPrev = &m_PlayInfoList;
  205. $$ENDIF
  206. $$IF(DPLAYVOICE)
  207.  
  208.     m_pNetVoice                 = NULL;
  209. $$ENDIF
  210.  
  211.     // Read settings from registry
  212.     ReadSettings();
  213. }
  214.  
  215.  
  216.  
  217.  
  218. //-----------------------------------------------------------------------------
  219. // Name: OneTimeSceneInit()
  220. // Desc: Called during initial app startup, this function performs all the
  221. //       permanent initialization.
  222. //-----------------------------------------------------------------------------
  223. HRESULT CMyApplication::OneTimeSceneInit()
  224. {
  225.     // TODO: perform one time initialization
  226.  
  227.     // Drawing loading status message until app finishes loading
  228.     SendMessage( m_hWnd, WM_PAINT, 0, 0 );
  229.  
  230. $$IF(DPLAY)
  231.     // Init COM so we can use CoCreateInstance.  And be sure to init 
  232.     // COM as multithreaded when using DirectPlay
  233.     HRESULT hr;
  234.     if( FAILED( hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ) ) )
  235.         return hr;
  236.  
  237. $$ENDIF
  238. $$IF(DINPUT)
  239.     // Initialize DirectInput
  240.     InitInput( m_hWnd );
  241.  
  242. $$ENDIF
  243. $$IF(DMUSIC || DSOUND)
  244.     // Initialize audio
  245.     InitAudio( m_hWnd );
  246.  
  247. $$ENDIF
  248. $$IF(DPLAY)
  249.     // Initialize DirectPlay
  250.     InitDirectPlay();
  251.  
  252.     // Create a new DirectPlay session or join to an existing DirectPlay session
  253.     if( FAILED( hr = ConnectViaDirectPlay() ) )
  254.         return hr;
  255.  
  256. $$ENDIF
  257.     m_bLoadingApp = FALSE;
  258.  
  259.     return S_OK;
  260. }
  261.  
  262.  
  263.  
  264.  
  265. //-----------------------------------------------------------------------------
  266. // Name: ReadSettings()
  267. // Desc: Read the app settings from the registry
  268. //-----------------------------------------------------------------------------
  269. VOID CMyApplication::ReadSettings()
  270. {
  271.     HKEY hkey;
  272.     if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, DXAPP_KEY, 
  273.         0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  274.     {
  275.         // TODO: change as needed
  276.  
  277.         // Read the stored window width/height.  This is just an example,
  278.         // of how to use DXUtil_Read*() functions.
  279.         DXUtil_ReadIntRegKey( hkey, TEXT("Width"), &m_dwCreationWidth, m_dwCreationWidth );
  280.         DXUtil_ReadIntRegKey( hkey, TEXT("Height"), &m_dwCreationHeight, m_dwCreationHeight );
  281.  
  282. $$IF(DPLAY)
  283.         // Read the saved strings needed by DirectPlay
  284.         DXUtil_ReadStringRegKey( hkey, TEXT("Player Name"), 
  285.                                  m_strLocalPlayerName, MAX_PATH, TEXT("$$root$$ Player") );
  286.         DXUtil_ReadStringRegKey( hkey, TEXT("Session Name"), 
  287.                                  m_strSessionName, MAX_PATH, TEXT("$$root$$ Game") );
  288.         DXUtil_ReadStringRegKey( hkey, TEXT("Preferred Provider"), 
  289.                                  m_strPreferredProvider, MAX_PATH, 
  290.                                  TEXT("DirectPlay8 TCP/IP Service Provider") );
  291.  
  292. $$ENDIF
  293.         RegCloseKey( hkey );
  294.     }
  295. }
  296.  
  297.  
  298.  
  299.  
  300. //-----------------------------------------------------------------------------
  301. // Name: WriteSettings()
  302. // Desc: Write the app settings to the registry
  303. //-----------------------------------------------------------------------------
  304. VOID CMyApplication::WriteSettings()
  305. {
  306.     HKEY hkey;
  307.     DWORD dwType = REG_DWORD;
  308.     DWORD dwLength = sizeof(DWORD);
  309.  
  310.     if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, DXAPP_KEY, 
  311.         0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  312.     {
  313.         // TODO: change as needed
  314.  
  315.         // Write the window width/height.  This is just an example,
  316.         // of how to use DXUtil_Write*() functions.
  317.         DXUtil_WriteIntRegKey( hkey, TEXT("Width"), m_dwCreationWidth );
  318.         DXUtil_WriteIntRegKey( hkey, TEXT("Height"), m_dwCreationHeight );
  319.  
  320. $$IF(DPLAY)
  321.         // Save the strings used by DirectPlay that were entered via the UI
  322.         DXUtil_WriteStringRegKey( hkey, TEXT("Player Name"), m_strLocalPlayerName );
  323.         DXUtil_WriteStringRegKey( hkey, TEXT("Session Name"), m_strSessionName );
  324.         DXUtil_WriteStringRegKey( hkey, TEXT("Preferred Provider"), m_strPreferredProvider );
  325.         
  326. $$ENDIF
  327.         RegCloseKey( hkey );
  328.     }
  329. }
  330.  
  331.  
  332.  
  333.  
  334.  
  335. $$IF(ACTIONMAPPER)
  336. //-----------------------------------------------------------------------------
  337. // Name: StaticInputAddDeviceCB()
  338. // Desc: Static callback helper to call into CMyApplication class
  339. //-----------------------------------------------------------------------------
  340. HRESULT CALLBACK CMyApplication::StaticInputAddDeviceCB( 
  341.                                          CInputDeviceManager::DeviceInfo* pDeviceInfo, 
  342.                                          const DIDEVICEINSTANCE* pdidi, 
  343.                                          LPVOID pParam )
  344. {
  345.     CMyApplication * pApp = (CMyApplication*) pParam;
  346.     return pApp->InputAddDeviceCB( pDeviceInfo, pdidi );
  347. }
  348.  
  349.  
  350.  
  351.  
  352. //-----------------------------------------------------------------------------
  353. // Name: InputAddDeviceCB()
  354. // Desc: Called from CInputDeviceManager whenever a device is added. 
  355. //       Set the dead zone, and creates a new InputDeviceState for each device
  356. //-----------------------------------------------------------------------------
  357. HRESULT CMyApplication::InputAddDeviceCB( CInputDeviceManager::DeviceInfo* pDeviceInfo, 
  358.                                                    const DIDEVICEINSTANCE* pdidi )
  359. {
  360.     // Setup the deadzone 
  361.     DIPROPDWORD dipdw;
  362.     dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
  363.     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  364.     dipdw.diph.dwObj        = 0;
  365.     dipdw.diph.dwHow        = DIPH_DEVICE;
  366.     dipdw.dwData            = 500;
  367.     pDeviceInfo->pdidDevice->SetProperty( DIPROP_DEADZONE, &dipdw.diph );
  368.  
  369.     // Create a new InputDeviceState for each device so the 
  370.     // app can record its state 
  371.     InputDeviceState* pNewInputDeviceState = new InputDeviceState;
  372.     ZeroMemory( pNewInputDeviceState, sizeof(InputDeviceState) );
  373.     pDeviceInfo->pParam = (LPVOID) pNewInputDeviceState;
  374.  
  375.     return S_OK;
  376. }
  377.  
  378.  
  379.  
  380.  
  381. $$ENDIF
  382. $$IF(DINPUT)
  383. //-----------------------------------------------------------------------------
  384. // Name: InitInput()
  385. // Desc: Initialize DirectInput objects
  386. //-----------------------------------------------------------------------------
  387. HRESULT CMyApplication::InitInput( HWND hWnd )
  388. {
  389.     HRESULT hr;
  390.  
  391. $$IF(KEYBOARD)
  392.     // Create a IDirectInput8*
  393.     if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, 
  394.                                          IID_IDirectInput8, (VOID**)&m_pDI, NULL ) ) )
  395.         return DXTRACE_ERR_NOMSGBOX( "DirectInput8Create", hr );
  396.     
  397.     // Create a IDirectInputDevice8* for the keyboard
  398.     if( FAILED( hr = m_pDI->CreateDevice( GUID_SysKeyboard, &m_pKeyboard, NULL ) ) )
  399.         return DXTRACE_ERR_NOMSGBOX( "CreateDevice", hr );
  400.     
  401.     // Set the keyboard data format
  402.     if( FAILED( hr = m_pKeyboard->SetDataFormat( &c_dfDIKeyboard ) ) )
  403.         return DXTRACE_ERR_NOMSGBOX( "SetDataFormat", hr );
  404.     
  405.     // Set the cooperative level on the keyboard
  406.     if( FAILED( hr = m_pKeyboard->SetCooperativeLevel( hWnd, 
  407.                                             DISCL_NONEXCLUSIVE | 
  408.                                             DISCL_FOREGROUND | 
  409.                                             DISCL_NOWINKEY ) ) )
  410.         return DXTRACE_ERR_NOMSGBOX( "SetCooperativeLevel", hr );
  411.  
  412.     // Acquire the keyboard
  413.     m_pKeyboard->Acquire();
  414. $$ENDIF
  415. $$IF(ACTIONMAPPER)
  416.     // Setup action format for the actual gameplay
  417.     ZeroMemory( &m_diafGame, sizeof(DIACTIONFORMAT) );
  418.     m_diafGame.dwSize          = sizeof(DIACTIONFORMAT);
  419.     m_diafGame.dwActionSize    = sizeof(DIACTION);
  420.     m_diafGame.dwDataSize      = NUMBER_OF_GAMEACTIONS * sizeof(DWORD);
  421.     m_diafGame.guidActionMap   = g_guidApp;
  422.  
  423.     // TODO: change the genre as needed
  424.     m_diafGame.dwGenre         = DIVIRTUAL_CAD_3DCONTROL; 
  425.  
  426.     m_diafGame.dwNumActions    = NUMBER_OF_GAMEACTIONS;
  427.     m_diafGame.rgoAction       = g_rgGameAction;
  428.     m_diafGame.lAxisMin        = -100;
  429.     m_diafGame.lAxisMax        = 100;
  430.     m_diafGame.dwBufferSize    = 16;
  431.     _tcscpy( m_diafGame.tszActionMap, _T("$$root$$ Game") );
  432.  
  433.     // Create a new input device manager
  434.     m_pInputDeviceManager = new CInputDeviceManager();
  435.  
  436.     if( FAILED( hr = m_pInputDeviceManager->Create( hWnd, NULL, m_diafGame, 
  437.                                                     StaticInputAddDeviceCB, this ) ) )
  438.         return DXTRACE_ERR_NOMSGBOX( "m_pInputDeviceManager->Create", hr );
  439. $$ENDIF
  440.  
  441.     return S_OK;
  442. }
  443.  
  444.  
  445.  
  446.  
  447. $$ENDIF
  448. $$IF(DMUSIC || DSOUND)
  449. //-----------------------------------------------------------------------------
  450. // Name: InitAudio()
  451. // Desc: Initialize DirectX audio objects
  452. //-----------------------------------------------------------------------------
  453. HRESULT CMyApplication::InitAudio( HWND hWnd )
  454. {
  455.     HRESULT hr;
  456.  
  457. $$IF(DMUSIC)
  458.     // Create the music manager class, used to create the sounds
  459.     m_pMusicManager = new CMusicManager();
  460.     if( FAILED( hr = m_pMusicManager->Initialize( hWnd ) ) )
  461.         return DXTRACE_ERR_NOMSGBOX( "m_pMusicManager->Initialize", hr );
  462.  
  463.     // Instruct the music manager where to find the files
  464.     // TODO: Set this to the media directory, or use resources
  465.     TCHAR szPath[MAX_PATH];
  466.     GetCurrentDirectory( MAX_PATH, szPath ); 
  467.     m_pMusicManager->SetSearchDirectory( szPath );
  468.  
  469.     // TODO: load the sounds from resources (or files)
  470.     m_pMusicManager->CreateSegmentFromResource( &m_pBounceSound, _T("BOUNCE"), _T("WAVE") );
  471.  
  472. $$ELSE
  473.     // Create a static IDirectSound in the CSound class.  
  474.     // Set coop level to DSSCL_PRIORITY, and set primary buffer 
  475.     // format to stereo, 22kHz and 16-bit output.
  476.     m_pSoundManager = new CSoundManager();
  477.  
  478.     if( FAILED( hr = m_pSoundManager->Initialize( hWnd, DSSCL_PRIORITY, 2, 22050, 16 ) ) )
  479.         return DXTRACE_ERR_NOMSGBOX( TEXT("m_pSoundManager->Initialize"), hr );
  480.  
  481.     // TODO: load the sounds from resources (or files)
  482.     m_pSoundManager->Create( &m_pBounceSound, TEXT("BOUNCE"), 0, GUID_NULL, 5 );
  483.  
  484. $$ENDIF
  485.     return S_OK;
  486. }
  487.  
  488.  
  489.  
  490.  
  491. $$ENDIF
  492. $$IF(DPLAY)
  493. //-----------------------------------------------------------------------------
  494. // Name: InitDirectPlay()
  495. // Desc: Initialize DirectPlay
  496. //-----------------------------------------------------------------------------
  497. HRESULT CMyApplication::InitDirectPlay()
  498. {
  499.     // Initialize critical sections
  500.     InitializeCriticalSection( &g_csPlayerContext );
  501.     InitializeCriticalSection( &g_csWorldStateContext );
  502.  
  503.     // Create helper class
  504.     m_pNetConnectWizard = new CNetConnectWizard( g_hInst, m_hWnd, 
  505.                                                  m_strWindowTitle, &g_guidApp );
  506. $$IF(DPLAYVOICE)
  507.     m_pNetVoice         = new CNetVoice( StaticDirectPlayVoiceClientMessageHandler, StaticDirectPlayVoiceServerMessageHandler );
  508. $$ENDIF
  509.  
  510.     DPNHANDLE hLobbyLaunchedConnection = NULL;
  511.     HRESULT hr;
  512.  
  513.     // Create IDirectPlay8Peer
  514.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Peer, NULL, 
  515.                                        CLSCTX_INPROC_SERVER,
  516.                                        IID_IDirectPlay8Peer, 
  517.                                        (LPVOID*) &m_pDP ) ) )
  518.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  519.  
  520.     // Create IDirectPlay8LobbiedApplication
  521.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8LobbiedApplication, NULL, 
  522.                                        CLSCTX_INPROC_SERVER,
  523.                                        IID_IDirectPlay8LobbiedApplication, 
  524.                                        (LPVOID*) &m_pLobbiedApp ) ) )
  525.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  526.  
  527.     // Init the helper class, now that m_pDP and m_pLobbiedApp are valid
  528.     m_pNetConnectWizard->Init( m_pDP, m_pLobbiedApp );
  529.  
  530.     // Init IDirectPlay8Peer
  531.     if( FAILED( hr = m_pDP->Initialize( NULL, StaticDirectPlayMessageHandler, 0 ) ) )
  532.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  533.  
  534.     // Init IDirectPlay8LobbiedApplication.  Before this Initialize() returns 
  535.     // a DPL_MSGID_CONNECT msg may come in to the DirectPlayLobbyMessageHandler 
  536.     // so be prepared ahead of time.
  537.     if( FAILED( hr = m_pLobbiedApp->Initialize( NULL, StaticDirectPlayLobbyMessageHandler, 
  538.                                                 &hLobbyLaunchedConnection, 0 ) ) )
  539.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  540.  
  541.     // IDirectPlay8LobbiedApplication::Initialize returns a handle to a connection
  542.     // if we have been lobby launched.  Initialize is guaranteed to return after 
  543.     // the DPL_MSGID_CONNECT msg has been processed.  So unless a we are expected 
  544.     // multiple lobby connections, we do not need to remember the lobby connection
  545.     // handle since it will be recorded upon the DPL_MSGID_CONNECT msg.
  546.     m_bWasLobbyLaunched = ( hLobbyLaunchedConnection != NULL );
  547.  
  548.     return S_OK;
  549. }
  550.  
  551.  
  552.  
  553.  
  554. //-----------------------------------------------------------------------------
  555. // Name: ConnectViaDirectPlay()
  556. // Desc: Create a new DirectPlay session or join to an existing DirectPlay session
  557. //-----------------------------------------------------------------------------
  558. HRESULT CMyApplication::ConnectViaDirectPlay()
  559. {
  560.     HRESULT hr;
  561.     BOOL bWasFullscreen  = FALSE;
  562.     BOOL bConnectSuccess = FALSE;
  563.  
  564.     // If we were launched from a lobby client, then we may have connection settings
  565.     // that we can use either host or join a game.  If not, then we'll need to prompt 
  566.     // the user to determine how to connect.
  567.     if( m_bWasLobbyLaunched && m_pNetConnectWizard->HaveConnectionSettingsFromLobby() )
  568.     {
  569.         // If were lobby launched then the DPL_MSGID_CONNECT has already been
  570.         // handled, and since the lobby client also sent us connection settings
  571.         // we can use them to either host or join a DirectPlay session. 
  572.         if( FAILED( hr = m_pNetConnectWizard->ConnectUsingLobbySettings() ) )
  573.         {
  574.             DXTRACE_ERR( TEXT("ConnectUsingLobbySettings"), hr );
  575.             MessageBox( m_hWnd, TEXT("Failed to connect using lobby settings. ")
  576.                         TEXT("The sample will now quit."),
  577.                         TEXT("$$root$$"), MB_OK | MB_ICONERROR );
  578.  
  579.             bConnectSuccess = FALSE;
  580.         }
  581.         else
  582.         {
  583.             // Read information from m_pNetConnectWizard
  584.             _tcscpy( m_strLocalPlayerName, m_pNetConnectWizard->GetPlayerName() );
  585.  
  586.             bConnectSuccess = TRUE; 
  587.         }
  588.     }
  589.     else
  590.     {
  591.         // If not lobby launched, prompt the user about the network 
  592.         // connection and which session they would like to join or 
  593.         // if they want to create a new one.
  594.  
  595.         // Setup connection wizard
  596.         m_pNetConnectWizard->SetPlayerName( m_strLocalPlayerName );
  597.         m_pNetConnectWizard->SetSessionName( m_strSessionName );
  598.         m_pNetConnectWizard->SetPreferredProvider( m_strPreferredProvider );
  599.  
  600.         // Start a connection wizard.  The wizard uses GDI dialog boxes.
  601.         // More complex games can use this as a starting point and add a 
  602.         // fancier graphics layer such as Direct3D.
  603.         hr = m_pNetConnectWizard->DoConnectWizard( FALSE );        
  604.         if( FAILED( hr ) ) 
  605.         {
  606.             DXTRACE_ERR( TEXT("DoConnectWizard"), hr );
  607.             MessageBox( m_hWnd, TEXT("Multiplayer connect failed. ")
  608.                         TEXT("The sample will now quit."),
  609.                         TEXT("$$root$$"), MB_OK | MB_ICONERROR );
  610.             bConnectSuccess = FALSE;
  611.         } 
  612.         else if( hr == NCW_S_QUIT ) 
  613.         {
  614.             // The user canceled the Multiplayer connect
  615.             bConnectSuccess = FALSE;
  616.         }
  617.         else
  618.         {
  619.             bConnectSuccess = TRUE; 
  620.  
  621.             // Read information from m_pNetConnectWizard
  622.             _tcscpy( m_strLocalPlayerName, m_pNetConnectWizard->GetPlayerName() );
  623.             _tcscpy( m_strSessionName, m_pNetConnectWizard->GetSessionName() );
  624.             _tcscpy( m_strPreferredProvider, m_pNetConnectWizard->GetPreferredProvider() );
  625.  
  626.             // Write information to the registry
  627.             WriteSettings();
  628.         }
  629.     }
  630.  
  631. $$IF(DPLAYVOICE)
  632.     if( bConnectSuccess )
  633.     {
  634.         // Initialize DirectPlay voice
  635.         if( FAILED( hr = InitDirectPlayVoice() ) )
  636.         {
  637.             bConnectSuccess = FALSE;
  638.  
  639.             if( hr == DVERR_USERBACK )
  640.             {
  641.                 MessageBox( m_hWnd, TEXT("The user backed out of the wizard.  ")
  642.                             TEXT("This simple sample does not handle this case, so ")
  643.                             TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  644.             }
  645.             else if( hr == DVERR_USERCANCEL )
  646.             {
  647.                 MessageBox( m_hWnd, TEXT("The user canceled the wizard. ")
  648.                             TEXT("This simple sample does not handle this case, so ")
  649.                             TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  650.             }
  651.             else 
  652.             {
  653.                 DXTRACE_ERR( TEXT("m_pNetVoice->Init"), hr );
  654.             }
  655.         }
  656.  
  657.         if( m_pNetVoice->IsHalfDuplex() ) 
  658.         {
  659.             MessageBox( m_hWnd, TEXT("You are running in half duplex mode. ")
  660.                         TEXT("In half duplex mode no recording takes place."), 
  661.                         TEXT("blank"), MB_OK );
  662.         }
  663.     }
  664.  
  665. $$ENDIF
  666.     if( FALSE == bConnectSuccess )
  667.     {
  668.         // Quit the app
  669.         PostQuitMessage(0);
  670.     }
  671.  
  672.     return S_OK;
  673. }
  674.  
  675.  
  676.  
  677.  
  678. $$ENDIF
  679. $$IF(DPLAYVOICE)
  680. //-----------------------------------------------------------------------------
  681. // Name: InitDirectPlayVoice()
  682. // Desc: Init DirectPlay Voice
  683. //-----------------------------------------------------------------------------
  684. HRESULT CMyApplication::InitDirectPlayVoice()
  685. {
  686.     HRESULT hr;
  687.  
  688.     // Set default DirectPlayVoice setup options
  689.     // TODO: change as needed or ask user for settings
  690.     ZeroMemory( &m_dvClientConfig, sizeof(m_dvClientConfig) );
  691.     m_dvClientConfig.dwSize                 = sizeof(m_dvClientConfig);
  692.     m_dvClientConfig.dwFlags                = DVCLIENTCONFIG_AUTOVOICEACTIVATED |
  693.                                               DVCLIENTCONFIG_AUTORECORDVOLUME;
  694.     m_dvClientConfig.lPlaybackVolume        = DVPLAYBACKVOLUME_DEFAULT;
  695.     m_dvClientConfig.dwBufferQuality        = DVBUFFERQUALITY_DEFAULT;
  696.     m_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  697.     m_dvClientConfig.dwThreshold            = DVTHRESHOLD_UNUSED;
  698.     m_dvClientConfig.lRecordVolume          = DVRECORDVOLUME_LAST;
  699.     m_dvClientConfig.dwNotifyPeriod         = 0;
  700.  
  701.     m_guidDVSessionCT                       = DPVCTGUID_DEFAULT;
  702.  
  703.     // Creates and connects to DirectPlay Voice using the settings stored 
  704.     // in m_guidDVSessionCT & m_dvClientConfig.  It also runs the DirectPlay
  705.     // Voice wizard if it hasn't been run before on this machine
  706.     if( FAILED( hr = m_pNetVoice->Init( m_hWnd, m_pNetConnectWizard->IsHostPlayer(), TRUE,
  707.                                         m_pDP, DVSESSIONTYPE_PEER, 
  708.                                         &m_guidDVSessionCT, &m_dvClientConfig ) ) )
  709.         return hr;
  710.  
  711.     return S_OK;
  712. }
  713.  
  714.  
  715.  
  716.  
  717. $$ENDIF
  718. //-----------------------------------------------------------------------------
  719. // Name: FrameMove()
  720. // Desc: Called once per frame, the call is the entry point for animating
  721. //       the scene.
  722. //-----------------------------------------------------------------------------
  723. HRESULT CMyApplication::FrameMove()
  724. {
  725.     // TODO: update world
  726.  
  727.     // Update user input state
  728.     UpdateInput( &m_UserInput );
  729.  
  730. $$IF(DPLAY)
  731.     // Send local input to all network players if it changed
  732.     SendLocalInputIfChanged();
  733.  
  734.     if( m_pNetConnectWizard->IsHostPlayer() )
  735.     {
  736.         m_fWorldSyncTimer -= m_fElapsedTime;
  737.         if( m_fWorldSyncTimer < 0.0f )
  738.         {
  739.             // If this player is the host and timer has expired
  740.             // then reset timer and send the world state to all players
  741.             m_fWorldSyncTimer = 0.1f;
  742.             SendWorldStateToAll();
  743.         }
  744.     }
  745.  
  746. $$ENDIF
  747. $$IF(ACTIONMAPPER)
  748.     // Respond to input
  749.     if( m_UserInput.bDoConfigureInput )
  750.     {
  751.         // One-shot per keypress
  752.         m_UserInput.bDoConfigureInput = FALSE;
  753.  
  754.         Pause( TRUE );
  755.  
  756.         // Get access to the list of semantically-mapped input devices
  757.         // to delete all InputDeviceState structs before calling ConfigureDevices()
  758.         CInputDeviceManager::DeviceInfo* pDeviceInfos;
  759.         DWORD dwNumDevices;
  760.         m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  761.  
  762.         for( DWORD i=0; i<dwNumDevices; i++ )
  763.         {
  764.             InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  765.             SAFE_DELETE( pInputDeviceState );
  766.             pDeviceInfos[i].pParam = NULL;
  767.         }
  768.  
  769.         // Configure the devices (with edit capability)
  770.         m_pInputDeviceManager->ConfigureDevices( m_hWnd, NULL, NULL, DICD_EDIT, NULL );
  771.  
  772.         Pause( FALSE );
  773.     }
  774.  
  775. $$ENDIF
  776. $$IF(DPLAYVOICE)
  777.     if( m_UserInput.bDoConfigureVoice )
  778.     {
  779.         // One-shot per keypress
  780.         m_UserInput.bDoConfigureVoice = FALSE;
  781.  
  782.         Pause(TRUE);
  783.  
  784.         // Allow user to configure the voice settings
  785.         UserConfigVoice();
  786.  
  787.         Pause(FALSE);
  788.     }
  789.  
  790. $$ENDIF
  791. $$IF(DPLAY)
  792.     // Combining the input data from all players 
  793.     // TODO: Combining the input data from all players is an unrealistic yet simple 
  794.     //       usage of network data. Use it as a starting point to serve your needs
  795.     CombineInputFromAllPlayers( &m_CombinedNetworkInput );
  796.  
  797. $$ENDIF
  798. $$IF(DPLAYVOICE)
  799.     // Update talking varibles 
  800.     // TODO: The talking variables just update the text, but something more complex
  801.     //       like animation could be done based on them
  802.     UpdateTalkingVariables();
  803.  
  804. $$ENDIF
  805.     // Update the world state according to user input
  806.  
  807. $$IF(DPLAY)
  808.     // Enter world state critical section before accessing world state data 
  809.     // otherwise one of the DirectPlay threads may change the data
  810.     // while this thread is accessing or changing it.
  811.     WORLD_LOCK();
  812.  
  813.     // Rotate object according to user input from all network players
  814.     // Only update the world state if the host hasn't told our to pause
  815.     if( FALSE == m_bHostPausing )
  816.     {
  817.         // Update the m_fWorldRotY & m_fWorldRotX according 
  818.         // to the combined input of all the network players
  819. $$IF(ACTIONMAPPER)
  820.         if( m_CombinedNetworkInput.fAxisRotateLR )
  821.             m_fWorldRotY += m_fElapsedTime * m_CombinedNetworkInput.fAxisRotateLR;
  822.  
  823.         if( m_CombinedNetworkInput.fAxisRotateUD )
  824.             m_fWorldRotX += m_fElapsedTime * m_CombinedNetworkInput.fAxisRotateUD;
  825. $$ELSE // start !ACTIONMAPPER
  826.         if( m_CombinedNetworkInput.bRotateLeft && !m_CombinedNetworkInput.bRotateRight )
  827.             m_fWorldRotY += m_fElapsedTime;
  828.         else if( m_CombinedNetworkInput.bRotateRight && !m_CombinedNetworkInput.bRotateLeft )
  829.             m_fWorldRotY -= m_fElapsedTime;
  830.  
  831.         if( m_CombinedNetworkInput.bRotateUp && !m_CombinedNetworkInput.bRotateDown )
  832.             m_fWorldRotX += m_fElapsedTime;
  833.         else if( m_CombinedNetworkInput.bRotateDown && !m_CombinedNetworkInput.bRotateUp )
  834.             m_fWorldRotX -= m_fElapsedTime;
  835. $$ENDIF // end ACTIONMAPPER
  836.     }
  837.  
  838.     // Leave the critical section
  839.     WORLD_UNLOCK();
  840.  
  841. $$ENDIF // end DPLAY
  842. $$IF(!DPLAY)
  843. $$IF(ACTIONMAPPER)
  844.     if( m_UserInput.fAxisRotateLR )
  845.         m_fWorldRotY += m_fElapsedTime * m_UserInput.fAxisRotateLR;
  846.  
  847.     if( m_UserInput.fAxisRotateUD )
  848.         m_fWorldRotX += m_fElapsedTime * m_UserInput.fAxisRotateUD;
  849.  
  850. $$ELSE // start !ACTIONMAPPER
  851.     if( m_UserInput.bRotateLeft && !m_UserInput.bRotateRight )
  852.         m_fWorldRotY += m_fElapsedTime;
  853.     else if( m_UserInput.bRotateRight && !m_UserInput.bRotateLeft )
  854.         m_fWorldRotY -= m_fElapsedTime;
  855.  
  856.     if( m_UserInput.bRotateUp && !m_UserInput.bRotateDown )
  857.         m_fWorldRotX += m_fElapsedTime;
  858.     else if( m_UserInput.bRotateDown && !m_UserInput.bRotateUp )
  859.         m_fWorldRotX -= m_fElapsedTime;
  860.  
  861. $$ENDIF // end ACTIONMAPPER
  862. $$ENDIF // end !DPLAY
  863. $$IF(DMUSIC || DSOUND)
  864.     // Play the sound every so often while the button is pressed 
  865.     if( m_UserInput.bPlaySoundButtonDown )
  866.     {
  867.         m_fSoundPlayRepeatCountdown -= m_fElapsedTime;
  868.         if( m_fSoundPlayRepeatCountdown <= 0.0f )
  869.         {
  870.             m_fSoundPlayRepeatCountdown = 0.5f;
  871.             if( m_pBounceSound )
  872.                 m_pBounceSound->Play();
  873.         }
  874.     }
  875.     else
  876.     {
  877.         m_fSoundPlayRepeatCountdown = 0.0f;
  878.     }
  879.  
  880. $$ENDIF // DMUSIC || DSOUND
  881.     return S_OK;
  882. }
  883.  
  884.  
  885.  
  886.  
  887. //-----------------------------------------------------------------------------
  888. // Name: UpdateInput()
  889. // Desc: Update the user input.  Called once per frame 
  890. //-----------------------------------------------------------------------------
  891. void CMyApplication::UpdateInput( UserInput* pUserInput )
  892. {
  893. $$IF(ACTIONMAPPER)
  894.     if( NULL == m_pInputDeviceManager )
  895.         return;
  896.  
  897.     // Get access to the list of semantically-mapped input devices
  898.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  899.     DWORD dwNumDevices;
  900.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  901.  
  902.     // Loop through all devices and check game input
  903.     for( DWORD i=0; i<dwNumDevices; i++ )
  904.     {
  905.         DIDEVICEOBJECTDATA rgdod[10];
  906.         DWORD   dwItems = 10;
  907.         HRESULT hr;
  908.         LPDIRECTINPUTDEVICE8 pdidDevice = pDeviceInfos[i].pdidDevice;
  909.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  910.  
  911.         hr = pdidDevice->Acquire();
  912.         hr = pdidDevice->Poll();
  913.         hr = pdidDevice->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
  914.                                         rgdod, &dwItems, 0 );
  915.         if( FAILED(hr) )
  916.             continue;
  917.  
  918.         // Get the sematics codes for the game menu
  919.         for( DWORD j=0; j<dwItems; j++ )
  920.         {
  921.             BOOL  bButtonState = (rgdod[j].dwData==0x80) ? TRUE : FALSE;
  922.             FLOAT fButtonState = (rgdod[j].dwData==0x80) ? 1.0f : 0.0f;
  923.             FLOAT fAxisState   = (FLOAT)((int)rgdod[j].dwData)/100.0f;
  924.  
  925.             switch( rgdod[j].uAppData )
  926.             {
  927.                 // TODO: Handle semantics for the game 
  928.  
  929.                 // Handle relative axis data
  930.                 case INPUT_ROTATE_AXIS_LR: 
  931.                     pInputDeviceState->fAxisRotateLR = -fAxisState;
  932.                     break;
  933.                 case INPUT_ROTATE_AXIS_UD:
  934.                     pInputDeviceState->fAxisRotateUD = -fAxisState;
  935.                     break;
  936.  
  937.                 // Handle buttons separately so the button state data
  938.                 // doesn't overwrite the axis state data, and handle
  939.                 // each button separately so they don't overwrite each other
  940.                 case INPUT_ROTATE_LEFT:  pInputDeviceState->bButtonRotateLeft  = bButtonState; break;
  941.                 case INPUT_ROTATE_RIGHT: pInputDeviceState->bButtonRotateRight = bButtonState; break;
  942.                 case INPUT_ROTATE_UP:    pInputDeviceState->bButtonRotateUp    = bButtonState; break;
  943.                 case INPUT_ROTATE_DOWN:  pInputDeviceState->bButtonRotateDown  = bButtonState; break;
  944. $$IF(DMUSIC || DSOUND)
  945.                 case INPUT_PLAY_SOUND:   pInputDeviceState->bButtonPlaySoundButtonDown = bButtonState; break;
  946. $$ENDIF // DMUSIC || DSOUND
  947.  
  948.                 // Handle one-shot buttons
  949.                 case INPUT_CONFIG_INPUT:   if( bButtonState ) pUserInput->bDoConfigureInput = TRUE; break;
  950. $$IF(DPLAYVOICE)
  951.                 case INPUT_CONFIG_VOICE:   if( bButtonState ) pUserInput->bDoConfigureVoice   = TRUE; break;
  952. $$ENDIF
  953.             }
  954.         }
  955.     }
  956.  
  957.     // TODO: change process code as needed
  958.  
  959.     // Process user input and store result into pUserInput struct
  960.     pUserInput->fAxisRotateLR = 0.0f;
  961.     pUserInput->fAxisRotateUD = 0.0f;
  962. $$IF(DMUSIC || DSOUND)
  963.     pUserInput->bPlaySoundButtonDown = FALSE;
  964. $$ENDIF
  965.  
  966.     // Concatinate the data from all the DirectInput devices
  967.     for( i=0; i<dwNumDevices; i++ )
  968.     {
  969.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  970.  
  971.         // Use the axis data that is furthest from zero
  972.         if( fabs(pInputDeviceState->fAxisRotateLR) > fabs(pUserInput->fAxisRotateLR) )
  973.             pUserInput->fAxisRotateLR = pInputDeviceState->fAxisRotateLR;
  974.  
  975.         if( fabs(pInputDeviceState->fAxisRotateUD) > fabs(pUserInput->fAxisRotateUD) )
  976.             pUserInput->fAxisRotateUD = pInputDeviceState->fAxisRotateUD;
  977.  
  978.         // Process the button data 
  979.         if( pInputDeviceState->bButtonRotateLeft )
  980.             pUserInput->fAxisRotateLR = 1.0f;
  981.         else if( pInputDeviceState->bButtonRotateRight )
  982.             pUserInput->fAxisRotateLR = -1.0f;
  983.  
  984.         if( pInputDeviceState->bButtonRotateUp )
  985.             pUserInput->fAxisRotateUD = 1.0f;
  986.         else if( pInputDeviceState->bButtonRotateDown )
  987.             pUserInput->fAxisRotateUD = -1.0f;
  988.  
  989. $$IF(DMUSIC || DSOUND)
  990.         if( pInputDeviceState->bButtonPlaySoundButtonDown )
  991.             pUserInput->bPlaySoundButtonDown = TRUE;
  992. $$ENDIF // DMUSIC || DSOUND
  993.     } 
  994. $$ENDIF // ACTIONMAPPER
  995. $$IF(KEYBOARD)
  996.     HRESULT hr;
  997.  
  998.     // Get the input's device state, and put the state in dims
  999.     ZeroMemory( &pUserInput->diks, sizeof(pUserInput->diks) );
  1000.     hr = m_pKeyboard->GetDeviceState( sizeof(pUserInput->diks), &pUserInput->diks );
  1001.     if( FAILED(hr) ) 
  1002.     {
  1003.         m_pKeyboard->Acquire();
  1004.         return; 
  1005.     }
  1006.  
  1007.     // TODO: Process user input as needed
  1008.     pUserInput->bRotateLeft  = ( (pUserInput->diks[DIK_LEFT] & 0x80)  == 0x80 );
  1009.     pUserInput->bRotateRight = ( (pUserInput->diks[DIK_RIGHT] & 0x80) == 0x80 );
  1010.     pUserInput->bRotateUp    = ( (pUserInput->diks[DIK_UP] & 0x80)    == 0x80 );
  1011.     pUserInput->bRotateDown  = ( (pUserInput->diks[DIK_DOWN] & 0x80)  == 0x80 );
  1012. $$IF(DMUSIC || DSOUND)
  1013.     pUserInput->bPlaySoundButtonDown   = ( (pUserInput->diks[DIK_F5] & 0x80)     == 0x80 );
  1014. $$ENDIF // DMUSIC || DSOUND
  1015. $$ENDIF // KEYBOARD
  1016. $$IF(!DINPUT)
  1017.     pUserInput->bRotateUp    = ( m_bHasFocus && (GetAsyncKeyState( VK_UP )    & 0x8000) == 0x8000 );
  1018.     pUserInput->bRotateDown  = ( m_bHasFocus && (GetAsyncKeyState( VK_DOWN )  & 0x8000) == 0x8000 );
  1019.     pUserInput->bRotateLeft  = ( m_bHasFocus && (GetAsyncKeyState( VK_LEFT )  & 0x8000) == 0x8000 );
  1020.     pUserInput->bRotateRight = ( m_bHasFocus && (GetAsyncKeyState( VK_RIGHT ) & 0x8000) == 0x8000 );
  1021. $$IF(DMUSIC || DSOUND)
  1022.     pUserInput->bPlaySoundButtonDown = ( m_bHasFocus && (GetAsyncKeyState( VK_F5 ) & 0x8000) == 0x8000 );
  1023. $$ENDIF // DMUSIC || DSOUND
  1024. $$ENDIF // !DINPUT
  1025. }
  1026.  
  1027.  
  1028.  
  1029.  
  1030. $$IF(DPLAY)
  1031. //-----------------------------------------------------------------------------
  1032. // Name: SendLocalInputIfChanged()
  1033. // Desc: Send local input to all network players if it changed
  1034. //-----------------------------------------------------------------------------
  1035. HRESULT CMyApplication::SendLocalInputIfChanged()
  1036. {
  1037.     if( NULL == m_pLocalPlayerInfo )
  1038.         return S_OK;
  1039.  
  1040.     // Enter player critical section before accessing player's state data 
  1041.     // otherwise the DirectPlay network threads may change the data
  1042.     // while this thread is accessing it.
  1043.     PLAYER_LOCK();                  
  1044.  
  1045.     // Compare the local input axis data from DirectInput against the 
  1046.     // state of the axis data stored in the local player's 
  1047.     // APP_PLAYER_INFO struct to see if input changed
  1048.     BOOL bLocalInputChanged = FALSE;
  1049. $$IF(ACTIONMAPPER)
  1050.     if( m_UserInput.fAxisRotateLR != m_pLocalPlayerInfo->fAxisRotateLR ||
  1051.         m_UserInput.fAxisRotateUD != m_pLocalPlayerInfo->fAxisRotateUD )
  1052. $$ELSE
  1053.     if( m_UserInput.bRotateUp    != m_pLocalPlayerInfo->bRotateUp   ||
  1054.         m_UserInput.bRotateDown  != m_pLocalPlayerInfo->bRotateDown ||
  1055.         m_UserInput.bRotateLeft  != m_pLocalPlayerInfo->bRotateLeft ||
  1056.         m_UserInput.bRotateRight != m_pLocalPlayerInfo->bRotateRight )
  1057. $$ENDIF
  1058.     {
  1059.         bLocalInputChanged = TRUE;
  1060.     }
  1061.  
  1062.     PLAYER_UNLOCK();                // leave player context CS
  1063.  
  1064.     // If it has changed then send it to all the network players
  1065.     // including the local player
  1066.     if( bLocalInputChanged )
  1067.     {
  1068.         GAMEMSG_INPUTSTATE msgInputState;
  1069.         msgInputState.nType = GAME_MSGID_INPUTSTATE;
  1070. $$IF(ACTIONMAPPER)
  1071.         msgInputState.fAxisRotateLR = m_UserInput.fAxisRotateLR;
  1072.         msgInputState.fAxisRotateUD = m_UserInput.fAxisRotateUD;
  1073. $$ELSE
  1074.         msgInputState.bRotateUp    = m_UserInput.bRotateUp;
  1075.         msgInputState.bRotateDown  = m_UserInput.bRotateDown;
  1076.         msgInputState.bRotateLeft  = m_UserInput.bRotateLeft;
  1077.         msgInputState.bRotateRight = m_UserInput.bRotateRight;
  1078. $$ENDIF
  1079.  
  1080.         DPN_BUFFER_DESC bufferDesc;
  1081.         bufferDesc.dwBufferSize = sizeof(GAMEMSG_INPUTSTATE);
  1082.         bufferDesc.pBufferData  = (BYTE*) &msgInputState;
  1083.  
  1084.         // Send it to all of the players including the local client
  1085.         // DirectPlay will tell via the message handler 
  1086.         // if there are any severe errors, so ignore any errors 
  1087.         DPNHANDLE hAsync;
  1088.         m_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  1089.                        0, NULL, &hAsync, DPNSEND_GUARANTEED );
  1090.     }
  1091.  
  1092.  
  1093.     return S_OK;
  1094. }
  1095.  
  1096.  
  1097.  
  1098.  
  1099. //-----------------------------------------------------------------------------
  1100. // Name: SendWorldStateToAll()
  1101. // Desc: Send the world state to all players on the network
  1102. //-----------------------------------------------------------------------------
  1103. HRESULT CMyApplication::SendWorldStateToAll()
  1104. {
  1105.     // Enter world state critical section before accessing world state data 
  1106.     // otherwise one of the DirectPlay threads may change the data
  1107.     // while this thread is accessing it.
  1108.     WORLD_LOCK();
  1109.  
  1110.     GAMEMSG_WORLDSTATE msgWorldState;
  1111.     msgWorldState.nType = GAME_MSGID_WORLDSTATE;
  1112.     msgWorldState.fWorldRotX = m_fWorldRotX;
  1113.     msgWorldState.fWorldRotY = m_fWorldRotY;
  1114.  
  1115.     // Leave the critical section
  1116.     WORLD_UNLOCK();
  1117.  
  1118.     DPN_BUFFER_DESC bufferDesc;
  1119.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_WORLDSTATE);
  1120.     bufferDesc.pBufferData  = (BYTE*) &msgWorldState;
  1121.  
  1122.     // Send the message to all the players except the ourselves
  1123.     // DirectPlay will tell via the message handler 
  1124.     // if there are any severe errors, so ignore any errors 
  1125.     DPNHANDLE hAsync;
  1126.     m_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  1127.                    0, NULL, &hAsync, DPNSEND_NOLOOPBACK );
  1128.  
  1129.     return S_OK;
  1130. }
  1131.  
  1132.  
  1133.  
  1134.  
  1135. //-----------------------------------------------------------------------------
  1136. // Name: SendPauseMessageToAll()
  1137. // Desc: Send a pause message to all players on the network
  1138. //-----------------------------------------------------------------------------
  1139. HRESULT CMyApplication::SendPauseMessageToAll( BOOL bPause )
  1140. {
  1141.     GAMEMSG_HOSTPAUSE msgPause;
  1142.     msgPause.nType = GAME_MSGID_HOSTPAUSE;
  1143.     msgPause.bHostPause = bPause; 
  1144.  
  1145.     DPN_BUFFER_DESC bufferDesc;
  1146.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_HOSTPAUSE);
  1147.     bufferDesc.pBufferData  = (BYTE*) &msgPause;
  1148.  
  1149.     // Send the message to all the players except the ourselves
  1150.     // DirectPlay will tell via the message handler 
  1151.     // if there are any severe errors, so ignore any errors 
  1152.     DPNHANDLE hAsync;
  1153.     m_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  1154.                    0, NULL, &hAsync, DPNSEND_GUARANTEED | DPNSEND_NOLOOPBACK );
  1155.  
  1156.     return S_OK;
  1157. }
  1158.  
  1159.  
  1160.  
  1161.  
  1162. $$IF(ACTIONMAPPER)
  1163. //-----------------------------------------------------------------------------
  1164. // Name: CombineInputFromAllPlayers()
  1165. // Desc: Combine axis input from all network players
  1166. //-----------------------------------------------------------------------------
  1167. HRESULT CMyApplication::CombineInputFromAllPlayers( UserInput* pCombinedUserInput )
  1168. {
  1169.     FLOAT fAxisRotateLRCombined = 0.0f;
  1170.     FLOAT fAxisRotateUDCombined = 0.0f;
  1171.  
  1172.     // Enter player context CS before accessing APP_PLAYER_INFO structs
  1173.     // otherwise one of the DirectPlay threads may delete the struct
  1174.     // while this thread is accessing it.
  1175.     PLAYER_LOCK();                  
  1176.  
  1177.     APP_PLAYER_INFO* pPlayerInfo = m_PlayInfoList.pNext;
  1178.  
  1179.     while( pPlayerInfo != &m_PlayInfoList )
  1180.     {
  1181.         // Use the player whose axis data that is furthest from zero
  1182.         // and if one player is at -1, and another is at +1 then always
  1183.         // choose the positive one.
  1184.         if( fabs(pPlayerInfo->fAxisRotateLR) == fabs(fAxisRotateLRCombined) &&
  1185.                 pPlayerInfo->fAxisRotateLR > 0.0f )
  1186.             fAxisRotateLRCombined = pPlayerInfo->fAxisRotateLR;
  1187.         if( fabs(pPlayerInfo->fAxisRotateLR) > fabs(fAxisRotateLRCombined) )
  1188.             fAxisRotateLRCombined = pPlayerInfo->fAxisRotateLR;
  1189.  
  1190.         if( fabs(pPlayerInfo->fAxisRotateUD) == fabs(fAxisRotateUDCombined) && 
  1191.                 pPlayerInfo->fAxisRotateUD > 0.0f )
  1192.             fAxisRotateUDCombined = pPlayerInfo->fAxisRotateUD;
  1193.         if( fabs(pPlayerInfo->fAxisRotateUD) > fabs(fAxisRotateUDCombined) )
  1194.             fAxisRotateUDCombined = pPlayerInfo->fAxisRotateUD;
  1195.  
  1196.         pPlayerInfo = pPlayerInfo->pNext;
  1197.     }
  1198.  
  1199.     // Leave player context CS
  1200.     PLAYER_UNLOCK();           
  1201.     
  1202.     pCombinedUserInput->fAxisRotateLR = fAxisRotateLRCombined;
  1203.     pCombinedUserInput->fAxisRotateUD = fAxisRotateUDCombined;
  1204.  
  1205.     return S_OK;
  1206. }
  1207.  
  1208.  
  1209.  
  1210.  
  1211. $$ELSE // start !ACTIONMAPPER
  1212. //-----------------------------------------------------------------------------
  1213. // Name: CombineInputFromAllPlayers()
  1214. // Desc: Combine axis input from all network players
  1215. //-----------------------------------------------------------------------------
  1216. HRESULT CMyApplication::CombineInputFromAllPlayers( UserInput* pCombinedUserInput )
  1217. {
  1218.     pCombinedUserInput->bRotateUp    = FALSE;
  1219.     pCombinedUserInput->bRotateDown  = FALSE;
  1220.     pCombinedUserInput->bRotateLeft  = FALSE;
  1221.     pCombinedUserInput->bRotateRight = FALSE;
  1222.  
  1223.     // Enter player context CS before accessing APP_PLAYER_INFO structs
  1224.     // otherwise one of the DirectPlay threads may delete the struct
  1225.     // while this thread is accessing it.
  1226.     PLAYER_LOCK();                  
  1227.  
  1228.     APP_PLAYER_INFO* pPlayerInfo = m_PlayInfoList.pNext;
  1229.  
  1230.     while( pPlayerInfo != &m_PlayInfoList )
  1231.     {
  1232.         // Use the player whose axis data that is furthest from zero
  1233.         // and if one player is at -1, and another is at +1 then always
  1234.         // choose the positive one.
  1235.         if( pPlayerInfo->bRotateUp )
  1236.             pCombinedUserInput->bRotateUp = TRUE;
  1237.         if( pPlayerInfo->bRotateDown )
  1238.             pCombinedUserInput->bRotateDown = TRUE;
  1239.         if( pPlayerInfo->bRotateLeft )
  1240.             pCombinedUserInput->bRotateLeft = TRUE;
  1241.         if( pPlayerInfo->bRotateRight )
  1242.             pCombinedUserInput->bRotateRight = TRUE;
  1243.  
  1244.         pPlayerInfo = pPlayerInfo->pNext;
  1245.     }
  1246.  
  1247.     // Leave player context CS
  1248.     PLAYER_UNLOCK();           
  1249.     
  1250.     return S_OK;
  1251. }
  1252.  
  1253.  
  1254.  
  1255.  
  1256. $$ENDIF // end ACTIONMAPPER
  1257. $$ENDIF // end DPLAY
  1258. $$IF(DPLAYVOICE)
  1259. //-----------------------------------------------------------------------------
  1260. // Name: UpdateTalkingVariables()
  1261. // Desc: Update m_bNetworkPlayersTalking and m_bLocalPlayerTalking
  1262. //-----------------------------------------------------------------------------
  1263. VOID CMyApplication::UpdateTalkingVariables()
  1264. {
  1265.     // Enter player critical section before accessing player's state data 
  1266.     // otherwise the DirectPlay network threads may change the data
  1267.     // while this thread is accessing it.
  1268.     PLAYER_LOCK();      
  1269.  
  1270.     APP_PLAYER_INFO* pPlayerInfo = m_PlayInfoList.pNext;
  1271.  
  1272.     m_bNetworkPlayersTalking = FALSE;
  1273.     while( pPlayerInfo != &m_PlayInfoList )
  1274.     {
  1275.         // If any player besides the local player is talking, then set
  1276.         // m_bNetworkPlayersTalking to TRUE
  1277.         if( pPlayerInfo != m_pLocalPlayerInfo && pPlayerInfo->bTalking )
  1278.             m_bNetworkPlayersTalking = TRUE;
  1279.  
  1280.         pPlayerInfo = pPlayerInfo->pNext;
  1281.     }
  1282.  
  1283.     // Update m_bLocalPlayerTalking
  1284.     m_bLocalPlayerTalking = m_pLocalPlayerInfo->bTalking;
  1285.  
  1286.     PLAYER_UNLOCK();                
  1287. }
  1288.  
  1289.  
  1290.  
  1291.  
  1292. $$ENDIF // DPLAYVOICE
  1293. //-----------------------------------------------------------------------------
  1294. // Name: Render()
  1295. // Desc: Called once per frame, the call is the entry point for rendering the 
  1296. //       world.
  1297. //-----------------------------------------------------------------------------
  1298. HRESULT CMyApplication::Render()
  1299. {
  1300.     // TODO: render world
  1301.  
  1302.     static COLORREF clrNormal  = RGB(255,255,0);
  1303. $$IF(DPLAY)
  1304.     static COLORREF clrWarning = RGB(0,255,255);
  1305. $$ENDIF
  1306.     TCHAR       szMsg[MAX_PATH] = TEXT("");
  1307.     HDC         hDC;
  1308.     RECT        rc;
  1309.  
  1310.     GetClientRect( m_hWnd, &rc ); 
  1311.     int nNextLine = rc.bottom;
  1312.  
  1313.     hDC = GetDC( m_hWnd );
  1314.  
  1315.     // Set background and text colors
  1316.     HBRUSH hBrushBackground = CreateSolidBrush( RGB(0,0,255) );
  1317.     FillRect( hDC, &rc, hBrushBackground );
  1318.     DeleteObject( hBrushBackground );
  1319.     SetBkColor( hDC, RGB(0,0,255) );
  1320.     SetTextColor( hDC, clrNormal );
  1321.  
  1322. $$IF(DPLAY)
  1323. $$IF(ACTIONMAPPER)
  1324. $$// ******************************************************
  1325.     sprintf( szMsg, TEXT("Network Combined L/R Axis: %0.2f U/D Axis: %0.2f "), 
  1326.               m_CombinedNetworkInput.fAxisRotateLR, m_CombinedNetworkInput.fAxisRotateUD );
  1327. $$// ------------------------------------------------------
  1328.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1329. $$// ------------------------------------------------------
  1330.  
  1331. $$ELSE // start !ACTIONMAPPER
  1332. $$// ******************************************************
  1333.     wsprintf( szMsg, TEXT("Network Combined Keys: U=%d D=%d L=%d R=%d"), 
  1334.               m_CombinedNetworkInput.bRotateUp, m_CombinedNetworkInput.bRotateDown, m_CombinedNetworkInput.bRotateLeft, m_CombinedNetworkInput.bRotateRight );
  1335. $$// ------------------------------------------------------
  1336.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1337. $$// ------------------------------------------------------
  1338.  
  1339. $$ENDIF // ACTIONMAPPER
  1340. $$ENDIF // DPLAY
  1341. $$IF(ACTIONMAPPER)
  1342. $$// ******************************************************
  1343. $$IF(DPLAY)
  1344.     sprintf( szMsg, TEXT("Local Left/Right Axis: %0.2f Up/Down Axis: %0.2f "), 
  1345.               m_UserInput.fAxisRotateLR, m_UserInput.fAxisRotateUD );
  1346. $$ELSE
  1347.     sprintf( szMsg, TEXT("Left/Right Axis: %0.2f Up/Down Axis: %0.2f "), 
  1348.               m_UserInput.fAxisRotateLR, m_UserInput.fAxisRotateUD );
  1349. $$ENDIF
  1350. $$// ------------------------------------------------------
  1351.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1352. $$// ------------------------------------------------------
  1353.  
  1354. $$ELSE // start !ACTIONMAPPER
  1355. $$IF(DPLAY)
  1356. $$// ******************************************************
  1357.     wsprintf( szMsg, TEXT("Local Arrow keys: U=%d D=%d L=%d R=%d"), 
  1358.               m_UserInput.bRotateUp, m_UserInput.bRotateDown, m_UserInput.bRotateLeft, m_UserInput.bRotateRight );
  1359. $$ELSE // DPLAY
  1360.     wsprintf( szMsg, TEXT("Arrow keys: Up=%d Down=%d Left=%d Right=%d"), 
  1361.               m_UserInput.bRotateUp, m_UserInput.bRotateDown, m_UserInput.bRotateLeft, m_UserInput.bRotateRight );
  1362. $$ENDIF // DPLAY
  1363. $$// ------------------------------------------------------
  1364.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1365. $$// ------------------------------------------------------
  1366.  
  1367. $$ENDIF // ACTIONMAPPER
  1368. $$IF(DPLAY)
  1369. $$// ******************************************************
  1370.     sprintf( szMsg, TEXT("%d player(s) in session %s"), 
  1371.                         m_lNumberOfActivePlayers, 
  1372.                         m_pNetConnectWizard->IsHostPlayer() ? TEXT("(Hosting)") : TEXT("") );
  1373. $$// ------------------------------------------------------
  1374.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1375. $$// ------------------------------------------------------
  1376.  
  1377. $$ENDIF // DPLAY
  1378. $$IF(DPLAYVOICE)
  1379. $$// ******************************************************
  1380.     sprintf( szMsg, TEXT("Local Player: %s  Network Players: %s"), 
  1381.                         m_bLocalPlayerTalking ? TEXT("Talking") : TEXT("Silent"), 
  1382.                         m_bNetworkPlayersTalking ? TEXT("Talking") : TEXT("Silent") );
  1383. $$// ------------------------------------------------------
  1384.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1385. $$// ------------------------------------------------------
  1386.  
  1387. $$ENDIF // DPLAYVOICE
  1388. $$IF(!SHOW_TRIANGLE)
  1389. $$IF(!SHOW_TEAPOT)
  1390. $$// ******************************************************
  1391.     sprintf( szMsg, TEXT("World State: %0.3f, %0.3f"), 
  1392.                     m_fWorldRotX, m_fWorldRotY );
  1393. $$// ------------------------------------------------------
  1394.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1395. $$// ------------------------------------------------------
  1396.  
  1397. $$ENDIF // !SHOW_TEAPOT
  1398. $$ENDIF // !SHOW_TRIANGLE
  1399. $$IF(SHOW_TRIANGLE || SHOW_TEAPOT)
  1400. $$IF(ACTIONMAPPER)
  1401. $$// ******************************************************
  1402.     lstrcpy( szMsg, TEXT("Use arrow keys or joystick to rotate object") );
  1403. $$// ------------------------------------------------------
  1404.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1405. $$// ------------------------------------------------------
  1406.  
  1407. $$ELSE // start !ACTIONMAPPER
  1408. $$// ******************************************************
  1409.     lstrcpy( szMsg, TEXT("Use arrow keys to rotate object") );
  1410. $$// ------------------------------------------------------
  1411.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1412. $$// ------------------------------------------------------
  1413.  
  1414. $$ENDIF // ACTIONMAPPER
  1415. $$ELSE // start !(SHOW_TRIANGLE || SHOW_TEAPOT)
  1416. $$IF(ACTIONMAPPER)
  1417. $$// ******************************************************
  1418.     lstrcpy( szMsg, TEXT("Use arrow keys or joystick to update input") );
  1419. $$// ------------------------------------------------------
  1420.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1421. $$// ------------------------------------------------------
  1422.  
  1423. $$ELSE // start !ACTIONMAPPER
  1424.     lstrcpy( szMsg, TEXT("Use arrow keys to update input") );
  1425. $$// ------------------------------------------------------
  1426.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1427. $$// ------------------------------------------------------
  1428.  
  1429. $$ENDIF // ACTIONMAPPER
  1430. $$ENDIF // SHOW_TRIANGLE || SHOW_TEAPOT
  1431. $$IF(DMUSIC || DSOUND)
  1432. $$// ******************************************************
  1433.     lstrcpy( szMsg, TEXT("Hold 'F5' down to play and repeat a sound") );
  1434. $$// ------------------------------------------------------
  1435.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1436. $$// ------------------------------------------------------
  1437.  
  1438. $$ENDIF // DMUSIC || DSOUND
  1439. $$IF(DPLAYVOICE)
  1440. $$// ******************************************************
  1441.     lstrcpy( szMsg, TEXT("Press 'F4' to configure voice") );
  1442. $$// ------------------------------------------------------
  1443.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1444. $$// ------------------------------------------------------
  1445.  
  1446. $$ENDIF // DPLAYVOICE
  1447. $$IF(ACTIONMAPPER)
  1448. $$// ******************************************************
  1449.     lstrcpy( szMsg, TEXT("Press 'F3' to configure input") );
  1450. $$// ------------------------------------------------------
  1451.     nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1452. $$// ------------------------------------------------------
  1453.  
  1454. $$ENDIF // ACTIONMAPPER
  1455. $$IF(DPLAY)
  1456.     if( m_bHostPausing )
  1457.     {
  1458. $$// ******************************************************
  1459.         lstrcpy( szMsg, TEXT("Paused waiting for host...") );
  1460. $$// ------------------------------------------------------
  1461.         SetTextColor( hDC, clrWarning );
  1462.         nNextLine -= 20; TextOut( hDC, 2, nNextLine, szMsg, lstrlen(szMsg) );
  1463. $$// ------------------------------------------------------   
  1464.     }
  1465.  
  1466. $$ENDIF // end DPLAY
  1467.     ReleaseDC( m_hWnd, hDC );
  1468.  
  1469.     return S_OK;
  1470. }
  1471.  
  1472.  
  1473.  
  1474.  
  1475. //-----------------------------------------------------------------------------
  1476. // Name: StaticMsgProc()
  1477. // Desc: Static msg handler which passes messages to the application class.
  1478. //-----------------------------------------------------------------------------
  1479. LRESULT CALLBACK StaticMsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1480. {
  1481.     return g_pApp->MsgProc( hWnd, uMsg, wParam, lParam );
  1482. }
  1483.  
  1484.  
  1485.  
  1486.  
  1487. //-----------------------------------------------------------------------------
  1488. // Name: MainWndproc()
  1489. // Desc: Callback for all Windows messages
  1490. //-----------------------------------------------------------------------------
  1491. LRESULT CMyApplication::MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  1492. {
  1493.     switch( msg )
  1494.     {
  1495.         // TODO: Repond to Windows messages as needed
  1496.  
  1497.         case WM_COMMAND:
  1498.         {
  1499.             switch( LOWORD(wParam) )
  1500.             {
  1501.                 case IDM_EXIT:
  1502.                     PostQuitMessage( 0 );
  1503.                     break;
  1504.  
  1505. $$IF(ACTIONMAPPER)
  1506.                 case IDM_CONFIGINPUT:
  1507.                     m_UserInput.bDoConfigureInput = TRUE;
  1508.                     break;
  1509. $$ENDIF 
  1510. $$IF(DPLAYVOICE)
  1511.  
  1512.                 case IDM_CONFIGVOICE:
  1513.                     m_UserInput.bDoConfigureVoice = TRUE;
  1514.                     break;
  1515. $$ENDIF
  1516.             }
  1517.             break;
  1518.         }
  1519.  
  1520.         case WM_ACTIVATEAPP:
  1521.             m_bHasFocus = wParam;
  1522.             break;
  1523.  
  1524.         case WM_ENTERSIZEMOVE:
  1525.         case WM_ENTERMENULOOP:
  1526.             // Halt frame movement while the app is sizing or moving
  1527.             // or when menus are displayed
  1528.             Pause( TRUE );
  1529.             break;
  1530.  
  1531.         case WM_EXITSIZEMOVE:
  1532.         case WM_EXITMENULOOP:
  1533.             Pause( FALSE );
  1534.             break;
  1535.  
  1536.         case WM_PAINT:
  1537.         {
  1538.             if( m_bLoadingApp )
  1539.             {
  1540.                 // Draw on the window tell the user that the app is loading
  1541.                 // TODO: change as needed
  1542.                 HDC hDC = GetDC( hWnd );
  1543.                 TCHAR strMsg[MAX_PATH];
  1544.                 wsprintf( strMsg, TEXT("Loading... Please wait") );
  1545.                 RECT rct;
  1546.                 GetClientRect( hWnd, &rct );
  1547.                 DrawText( hDC, strMsg, -1, &rct, DT_CENTER|DT_VCENTER|DT_SINGLELINE );
  1548.                 ReleaseDC( hWnd, hDC );
  1549.             }
  1550.             break;
  1551.         }
  1552.  
  1553.         case WM_DESTROY:
  1554.             PostQuitMessage( 0 );
  1555.             break;
  1556.     }
  1557.  
  1558.     return DefWindowProc( hWnd, msg, wParam, lParam );
  1559. }
  1560.  
  1561.  
  1562.  
  1563.  
  1564. //-----------------------------------------------------------------------------
  1565. // Name: Pause()
  1566. // Desc: Called in to toggle the pause state of the app.
  1567. //-----------------------------------------------------------------------------
  1568. VOID CMyApplication::Pause( BOOL bPause )
  1569. {
  1570.     static DWORD dwAppPausedCount = 0L;
  1571.  
  1572. $$IF(DPLAY)
  1573.     // Tell the other apps to pause or unpause if this is the host
  1574.     if( m_pNetConnectWizard && m_pNetConnectWizard->IsHostPlayer() )
  1575.         SendPauseMessageToAll( bPause );
  1576.  
  1577. $$ENDIF
  1578. $$IF(ACTIONMAPPER)
  1579.     // Get access to the list of semantically-mapped input devices
  1580.     // to zero the state of all InputDeviceState structs.  This is needed
  1581.     // because when using DISCL_FOREGROUND, the action mapper will not 
  1582.     // record actions when the focus switches, for example if a dialog appears.
  1583.     // This causes a problem when a button held down when loosing focus, and let
  1584.     // go when the focus is lost.  The app will not record that the button 
  1585.     // has been let go, so the state will be incorrect when focus returns.  
  1586.     // To fix this either use DISCL_BACKGROUND or zero the state when 
  1587.     // loosing focus.
  1588.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  1589.     DWORD dwNumDevices;
  1590.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  1591.  
  1592.     for( DWORD i=0; i<dwNumDevices; i++ )
  1593.     {
  1594.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  1595.         ZeroMemory( pInputDeviceState, sizeof(InputDeviceState) );
  1596.     }
  1597.  
  1598. $$ENDIF
  1599.     dwAppPausedCount += ( bPause ? +1 : -1 );
  1600.  
  1601.     // Handle the first pause request (of many, nestable pause requests)
  1602.     if( bPause && ( 1 == dwAppPausedCount ) )
  1603.     {
  1604.         // Stop the scene from animating
  1605.         DXUtil_Timer( TIMER_STOP );
  1606.     }
  1607.  
  1608.     if( 0 == dwAppPausedCount )
  1609.     {
  1610.         // Restart the timers
  1611.         DXUtil_Timer( TIMER_START );
  1612.     }
  1613. }
  1614.  
  1615.  
  1616.  
  1617.  
  1618. $$IF(DPLAYVOICE)
  1619. //-----------------------------------------------------------------------------
  1620. // Name: UserConfigVoice()
  1621. // Desc: Allow user to configure the voice settings
  1622. //-----------------------------------------------------------------------------
  1623. HRESULT CMyApplication::UserConfigVoice()
  1624. {
  1625.     HRESULT hr;
  1626.    
  1627.     // Configure the voice settings, store the settings in 
  1628.     // m_guidDVSessionCT & m_dvClientConfig
  1629.     if( m_pNetVoice )
  1630.     {
  1631.         hr = m_pNetVoice->DoVoiceSetupDialog( g_hInst, m_hWnd, &m_guidDVSessionCT, &m_dvClientConfig );
  1632.  
  1633.         // If the settings dialog was not canceled, then change the settings
  1634.         if( hr != DVERR_USERCANCEL )
  1635.             m_pNetVoice->ChangeVoiceClientSettings( &m_dvClientConfig );
  1636.     }
  1637.  
  1638.     return S_OK;
  1639. }
  1640.  
  1641.  
  1642.  
  1643.  
  1644. $$ENDIF
  1645. //-----------------------------------------------------------------------------
  1646. // Name: FinalCleanup()
  1647. // Desc: Called before the app exits, this function gives the app the chance
  1648. //       to cleanup after itself.
  1649. //-----------------------------------------------------------------------------
  1650. HRESULT CMyApplication::FinalCleanup()
  1651. {
  1652.     // TODO: Perform any final cleanup needed
  1653. $$IF(DINPUT)
  1654.     // Cleanup DirectInput
  1655.     CleanupDirectInput();
  1656.  
  1657. $$ENDIF
  1658. $$IF(DMUSIC || DSOUND)
  1659.     // Cleanup DirectX audio objects
  1660.     SAFE_DELETE( m_pBounceSound );
  1661. $$IF(DMUSIC)
  1662.     SAFE_DELETE( m_pMusicManager );
  1663. $$ELSE // start !DMUSIC
  1664.     SAFE_DELETE( m_pSoundManager );
  1665. $$ENDIF // end DMUSIC
  1666.  
  1667. $$ENDIF // end (DMUSIC || DSOUND)
  1668. $$IF(DPLAY)
  1669.     // Cleanup DirectPlay
  1670.     CleanupDirectPlay();
  1671.  
  1672.     // Cleanup COM
  1673.     CoUninitialize();
  1674.  
  1675. $$ENDIF
  1676.     // Write the settings to the registry
  1677.     WriteSettings();
  1678.  
  1679.     return S_OK;
  1680. }
  1681.  
  1682.  
  1683.  
  1684.  
  1685. $$IF(DPLAY)
  1686. //-----------------------------------------------------------------------------
  1687. // Name: CleanupDirectPlay()
  1688. // Desc: Cleanup DirectPlay 
  1689. //-----------------------------------------------------------------------------
  1690. VOID CMyApplication::CleanupDirectPlay()
  1691. {
  1692. $$IF(DPLAYVOICE)
  1693.     // Disconnect from the DirectPlayVoice session, 
  1694.     // and destroy it if we are the host player.
  1695.     SAFE_DELETE( m_pNetVoice ); 
  1696.  
  1697. $$ENDIF
  1698.     // Cleanup DirectPlay and helper classes
  1699.     if( m_pNetConnectWizard )
  1700.         m_pNetConnectWizard->Shutdown();
  1701.  
  1702.     if( m_pDP )
  1703.     {
  1704.         m_pDP->Close(0);
  1705.         SAFE_RELEASE( m_pDP );
  1706.     }
  1707.  
  1708.     if( m_pLobbiedApp )
  1709.     {
  1710.         m_pLobbiedApp->Close( 0 );
  1711.         SAFE_RELEASE( m_pLobbiedApp );
  1712.     }    
  1713.  
  1714.     PLAYER_LOCK();                  // enter player context CS
  1715.     PLAYER_RELEASE( m_pLocalPlayerInfo ); // Release player and cleanup if needed
  1716.     PLAYER_UNLOCK();                // leave player context CS
  1717.  
  1718.     // Don't delete the wizard until we know that 
  1719.     // DirectPlay is out of its message handlers.
  1720.     // This will be true after Close() has been called. 
  1721.     SAFE_DELETE( m_pNetConnectWizard );
  1722.     DeleteCriticalSection( &g_csPlayerContext );
  1723.     DeleteCriticalSection( &g_csWorldStateContext );
  1724.  
  1725.     if( m_hrNet == DPNERR_CONNECTIONLOST )
  1726.     {
  1727.         MessageBox( m_hWnd, TEXT("The DirectPlay session was lost. ")
  1728.                     TEXT("The sample will now quit."),
  1729.                     TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  1730.     }
  1731. }
  1732.  
  1733.  
  1734.  
  1735. $$ENDIF
  1736. $$IF(DINPUT)
  1737. //-----------------------------------------------------------------------------
  1738. // Name: CleanupDirectInput()
  1739. // Desc: Cleanup DirectInput 
  1740. //-----------------------------------------------------------------------------
  1741. VOID CMyApplication::CleanupDirectInput()
  1742. {
  1743. $$IF(KEYBOARD)
  1744.     // Cleanup DirectX input objects
  1745.     SAFE_RELEASE( m_pKeyboard );
  1746.     SAFE_RELEASE( m_pDI );
  1747. $$ENDIF
  1748. $$IF(ACTIONMAPPER)
  1749.     if( NULL == m_pInputDeviceManager )
  1750.         return;
  1751.  
  1752.     // Get access to the list of semantically-mapped input devices
  1753.     // to delete all InputDeviceState structs
  1754.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  1755.     DWORD dwNumDevices;
  1756.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  1757.  
  1758.     for( DWORD i=0; i<dwNumDevices; i++ )
  1759.     {
  1760.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  1761.         SAFE_DELETE( pInputDeviceState );
  1762.         pDeviceInfos[i].pParam = NULL;
  1763.     }
  1764.  
  1765.     // Cleanup DirectX input objects
  1766.     SAFE_DELETE( m_pInputDeviceManager );
  1767. $$ENDIF
  1768. }
  1769.  
  1770.  
  1771.  
  1772.  
  1773. $$ENDIF
  1774. $$IF(DPLAY)
  1775. //-----------------------------------------------------------------------------
  1776. // Name: StaticDirectPlayMessageHandler
  1777. // Desc: Static callback helper to call into CMyApplication class
  1778. //-----------------------------------------------------------------------------
  1779. HRESULT WINAPI CMyApplication::StaticDirectPlayMessageHandler( PVOID pvUserContext, 
  1780.                                                                   DWORD dwMessageId, 
  1781.                                                                   PVOID pMsgBuffer )
  1782. {
  1783.     if( g_pApp )
  1784.         return g_pApp->DirectPlayMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  1785.     return S_OK;
  1786. }
  1787.  
  1788.  
  1789.  
  1790.  
  1791. //-----------------------------------------------------------------------------
  1792. // Name: DirectPlayMessageHandler
  1793. // Desc: Handler for DirectPlay messages.  This function is called by
  1794. //       the DirectPlay message handler pool of threads, so be careful of thread
  1795. //       synchronization problems with shared memory
  1796. //-----------------------------------------------------------------------------
  1797. HRESULT CMyApplication::DirectPlayMessageHandler( PVOID pvUserContext, 
  1798.                                                      DWORD dwMessageId, 
  1799.                                                      PVOID pMsgBuffer )
  1800. {
  1801.     // Try not to stay in this message handler for too long, otherwise
  1802.     // there will be a backlog of data.  The best solution is to 
  1803.     // queue data as it comes in, and then handle it on other threads.
  1804.     
  1805.     // This function is called by the DirectPlay message handler pool of 
  1806.     // threads, so be careful of thread synchronization problems with shared memory
  1807.  
  1808.     switch( dwMessageId )
  1809.     {
  1810.         case DPN_MSGID_CREATE_PLAYER:
  1811.         {
  1812.             HRESULT hr;
  1813.             PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
  1814.             pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer;
  1815.  
  1816.             // Get the peer info and extract its name
  1817.             DWORD dwSize = 0;
  1818.             DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
  1819.             hr = m_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, 
  1820.                                      pdpPlayerInfo, &dwSize, 0 );
  1821.             if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  1822.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  1823.             pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  1824.             ZeroMemory( pdpPlayerInfo, dwSize );
  1825.             pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
  1826.             hr = m_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, 
  1827.                                      pdpPlayerInfo, &dwSize, 0 );
  1828.             if( FAILED(hr) )
  1829.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  1830.  
  1831.             // Create a new and fill in a APP_PLAYER_INFO
  1832.             APP_PLAYER_INFO* pPlayerInfo = new APP_PLAYER_INFO;
  1833.             ZeroMemory( pPlayerInfo, sizeof(APP_PLAYER_INFO) );
  1834.             pPlayerInfo->lRefCount   = 1;
  1835.             pPlayerInfo->dpnidPlayer = pCreatePlayerMsg->dpnidPlayer;
  1836.  
  1837.             // This stores a extra TCHAR copy of the player name for 
  1838.             // easier access.  This will be redundant copy since DPlay 
  1839.             // also keeps a copy of the player name in GetPeerInfo()
  1840.             DXUtil_ConvertWideStringToGeneric( pPlayerInfo->strPlayerName, 
  1841.                                                pdpPlayerInfo->pwszName, MAX_PATH );
  1842.  
  1843.             if( pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL )
  1844.             {
  1845.                 m_dpnidLocalPlayer = pCreatePlayerMsg->dpnidPlayer;
  1846.                 m_pLocalPlayerInfo = pPlayerInfo;
  1847.  
  1848.                 // Increase the ref if this is the local player, so the struct 
  1849.                 // won't be deleted when DirectPlay shuts down.  The
  1850.                 // main window thread will release the struct when it is done
  1851.                 pPlayerInfo->lRefCount++;
  1852.             }
  1853.             else
  1854.             {
  1855.                 if( m_pNetConnectWizard->IsHostPlayer() )
  1856.                 {
  1857.                     // If the local player is the host and 
  1858.                     // this DPN_MSGID_CREATE_PLAYER is not for the local player
  1859.                     // then set the m_fWorldSyncTimer to fire immediately so
  1860.                     // the new player will get the state of the world
  1861.                     m_fWorldSyncTimer = 0.0f;
  1862.                 }
  1863.             }
  1864.  
  1865.             // Add the APP_PLAYER_INFO to the circular linked list, m_PlayInfoList
  1866.             pPlayerInfo->pNext = m_PlayInfoList.pNext;
  1867.             pPlayerInfo->pPrev = &m_PlayInfoList;
  1868.             m_PlayInfoList.pNext->pPrev = pPlayerInfo;    
  1869.             m_PlayInfoList.pNext = pPlayerInfo;    
  1870.  
  1871.             SAFE_DELETE_ARRAY( pdpPlayerInfo );
  1872.  
  1873.             // Tell DirectPlay to store this pPlayerInfo 
  1874.             // pointer in the pvPlayerContext.
  1875.             pCreatePlayerMsg->pvPlayerContext = pPlayerInfo;
  1876.  
  1877.             // Update the number of active players, and if the app needs to 
  1878.             // tell the UI immediately about this, then post a message to 
  1879.             // the window thread.  This keeps the DirectPlay message handler 
  1880.             // from blocking
  1881.             InterlockedIncrement( &m_lNumberOfActivePlayers );
  1882.             break;
  1883.         }
  1884.  
  1885.         case DPN_MSGID_RECEIVE:
  1886.         {
  1887.             PDPNMSG_RECEIVE pReceiveMsg;
  1888.             pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;
  1889.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pReceiveMsg->pvPlayerContext;
  1890.  
  1891.             GAMEMSG_GENERIC* pMsg = (GAMEMSG_GENERIC*) pReceiveMsg->pReceiveData;
  1892.             switch( pMsg->nType )
  1893.             {
  1894.                 case GAME_MSGID_INPUTSTATE:
  1895.                 {
  1896.                     // Update the APP_PLAYER_INFO struct associated with this
  1897.                     // network player with the data send in the GAMEMSG_INPUTSTATE.
  1898.                     GAMEMSG_INPUTSTATE* pInputStateMsg = (GAMEMSG_INPUTSTATE*) pMsg;
  1899.  
  1900.                     // Enter player critical section before accessing player's state data 
  1901.                     // otherwise the main thread or other DirectPlay threads may access the data
  1902.                     // while this thread is changing it.
  1903.                     PLAYER_LOCK();                  
  1904.  
  1905. $$IF(ACTIONMAPPER)
  1906.                     pPlayerInfo->fAxisRotateLR = pInputStateMsg->fAxisRotateLR;
  1907.                     pPlayerInfo->fAxisRotateUD = pInputStateMsg->fAxisRotateUD;
  1908. $$ELSE
  1909.                     pPlayerInfo->bRotateUp    = pInputStateMsg->bRotateUp;
  1910.                     pPlayerInfo->bRotateDown  = pInputStateMsg->bRotateDown;
  1911.                     pPlayerInfo->bRotateLeft  = pInputStateMsg->bRotateLeft;
  1912.                     pPlayerInfo->bRotateRight = pInputStateMsg->bRotateRight;
  1913. $$ENDIF
  1914.  
  1915.                     PLAYER_UNLOCK();                // leave player context CS
  1916.                     break;
  1917.                 }
  1918.  
  1919.                 case GAME_MSGID_WORLDSTATE:
  1920.                 {
  1921.                     // Enter world state critical section before accessing world state data 
  1922.                     // otherwise the main thread or other DirectPlay threads may access the data
  1923.                     // while this thread is changing it.
  1924.                     WORLD_LOCK();
  1925.  
  1926.                     // Update the world state with the data from GAMEMSG_WORLDSTATE
  1927.                     GAMEMSG_WORLDSTATE* pMsgWorldState = (GAMEMSG_WORLDSTATE*) pMsg;
  1928.                     m_fWorldRotX = pMsgWorldState->fWorldRotX;
  1929.                     m_fWorldRotY = pMsgWorldState->fWorldRotY;
  1930.  
  1931.                     // Leave the critical section
  1932.                     WORLD_UNLOCK();
  1933.                     break;
  1934.                 }
  1935.  
  1936.                 case GAME_MSGID_HOSTPAUSE:
  1937.                 {
  1938.                     GAMEMSG_HOSTPAUSE* pMsgPause = (GAMEMSG_HOSTPAUSE*) pMsg;
  1939.  
  1940.                     // Update the pause state with the data from GAMEMSG_HOSTPAUSE
  1941.                     m_bHostPausing = pMsgPause->bHostPause;
  1942.                     break;
  1943.                 }
  1944.             }
  1945.             break;
  1946.         }
  1947.  
  1948.         case DPN_MSGID_DESTROY_PLAYER:
  1949.         {
  1950.             PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;
  1951.             pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;
  1952.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pDestroyPlayerMsg->pvPlayerContext;
  1953.  
  1954.             PLAYER_LOCK();                  // enter player context CS
  1955.  
  1956.             // Remove pPlayerInfo from the circular linked list
  1957.             pPlayerInfo->pNext->pPrev = pPlayerInfo->pPrev;
  1958.             pPlayerInfo->pPrev->pNext = pPlayerInfo->pNext;
  1959.  
  1960.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  1961.             PLAYER_UNLOCK();                // leave player context CS
  1962.  
  1963.             // Update the number of active players, and if the app needs to 
  1964.             // tell the UI immediately about this, then post a message to 
  1965.             // the window thread.  This keeps the DirectPlay message handler 
  1966.             // from blocking
  1967.             InterlockedDecrement( &m_lNumberOfActivePlayers );
  1968.             break;
  1969.         }
  1970.  
  1971.         case DPN_MSGID_TERMINATE_SESSION:
  1972.         {
  1973.             PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
  1974.             pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;
  1975.  
  1976.             m_hrNet = DPNERR_CONNECTIONLOST;
  1977.  
  1978.             // Close the window, which shuts down the app
  1979.             if( m_hWnd )
  1980.                 PostMessage( m_hWnd, WM_QUIT, 0, 0 );
  1981.             break;
  1982.         }
  1983.     }
  1984.  
  1985.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  1986.     // so it can be informed of messages such as DPN_MSGID_ENUM_HOSTS_RESPONSE.
  1987.     if( m_pNetConnectWizard )
  1988.         return m_pNetConnectWizard->MessageHandler( pvUserContext, dwMessageId, 
  1989.                                                     pMsgBuffer );
  1990.     
  1991.     return S_OK;
  1992. }
  1993.  
  1994.  
  1995.  
  1996.  
  1997. //-----------------------------------------------------------------------------
  1998. // Name: StaticDirectPlayLobbyMessageHandler
  1999. // Desc: Static callback helper to call into CMyApplication class
  2000. //-----------------------------------------------------------------------------
  2001. HRESULT WINAPI CMyApplication::StaticDirectPlayLobbyMessageHandler( PVOID pvUserContext, 
  2002.                                                                   DWORD dwMessageId, 
  2003.                                                                   PVOID pMsgBuffer )
  2004. {
  2005.     if( g_pApp )
  2006.         return g_pApp->DirectPlayLobbyMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  2007.     return S_OK;
  2008. }
  2009.  
  2010.  
  2011.  
  2012.  
  2013. //-----------------------------------------------------------------------------
  2014. // Name: DirectPlayLobbyMessageHandler
  2015. // Desc: Handler for DirectPlay lobby messages.  This function is called by
  2016. //       the DirectPlay lobby message handler pool of threads, so be careful of 
  2017. //       thread synchronization problems with shared memory
  2018. //-----------------------------------------------------------------------------
  2019. HRESULT CMyApplication::DirectPlayLobbyMessageHandler( PVOID pvUserContext, 
  2020.                                                           DWORD dwMessageId, 
  2021.                                                           PVOID pMsgBuffer )
  2022. {
  2023.     switch( dwMessageId )
  2024.     {
  2025.         case DPL_MSGID_CONNECT:
  2026.         {
  2027.             PDPL_MESSAGE_CONNECT pConnectMsg;
  2028.             pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
  2029.  
  2030.             // The CNetConnectWizard will handle this message for us,
  2031.             // so there is nothing we need to do here for this simple
  2032.             // sample.
  2033.             break;
  2034.         }
  2035.  
  2036.         case DPL_MSGID_DISCONNECT:
  2037.         {
  2038.             PDPL_MESSAGE_DISCONNECT pDisconnectMsg;
  2039.             pDisconnectMsg = (PDPL_MESSAGE_DISCONNECT)pMsgBuffer;
  2040.  
  2041.             // We should free any data associated with the lobby 
  2042.             // client here, but there is none.
  2043.             break;
  2044.         }
  2045.  
  2046.         case DPL_MSGID_RECEIVE:
  2047.         {
  2048.             PDPL_MESSAGE_RECEIVE pReceiveMsg;
  2049.             pReceiveMsg = (PDPL_MESSAGE_RECEIVE)pMsgBuffer;
  2050.  
  2051.             // The lobby client sent us data.  This sample doesn't
  2052.             // expected data from the client, but it is useful 
  2053.             // for more complex apps.
  2054.             break;
  2055.         }
  2056.  
  2057.         case DPL_MSGID_CONNECTION_SETTINGS:
  2058.         {
  2059.             PDPL_MESSAGE_CONNECTION_SETTINGS pConnectionStatusMsg;
  2060.             pConnectionStatusMsg = (PDPL_MESSAGE_CONNECTION_SETTINGS)pMsgBuffer;
  2061.  
  2062.             // The lobby client has changed the connection settings.  
  2063.             // This simple sample doesn't handle this, but more complex apps may
  2064.             // want to.
  2065.             break;
  2066.         }
  2067.     }
  2068.  
  2069.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  2070.     // so the wizard can be informed of lobby messages such as DPL_MSGID_CONNECT
  2071.     if( m_pNetConnectWizard )
  2072.         return m_pNetConnectWizard->LobbyMessageHandler( pvUserContext, dwMessageId, 
  2073.                                                          pMsgBuffer );
  2074.     
  2075.     return S_OK;
  2076. }
  2077.  
  2078.  
  2079.  
  2080.  
  2081. $$ENDIF
  2082. $$IF(DPLAYVOICE)
  2083. //-----------------------------------------------------------------------------
  2084. // Name: StaticDirectPlayVoiceServerMessageHandler
  2085. // Desc: Static callback helper to call into CMyApplication class
  2086. //-----------------------------------------------------------------------------
  2087. HRESULT WINAPI CMyApplication::StaticDirectPlayVoiceServerMessageHandler( PVOID pvUserContext, 
  2088.                                                                   DWORD dwMessageId, 
  2089.                                                                   PVOID pMsgBuffer )
  2090. {
  2091.     if( g_pApp )
  2092.         return g_pApp->DirectPlayVoiceServerMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  2093.     return S_OK;
  2094. }
  2095.  
  2096.  
  2097.  
  2098.  
  2099. //-----------------------------------------------------------------------------
  2100. // Name: DirectPlayVoiceServerMessageHandler()
  2101. // Desc: The callback for DirectPlayVoice server messages.  
  2102. //-----------------------------------------------------------------------------
  2103. HRESULT CMyApplication::DirectPlayVoiceServerMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  2104.                                                                 LPVOID lpMessage )
  2105. {
  2106.     // This simple sample doesn't respond to any server messages
  2107.     return S_OK;
  2108. }
  2109.  
  2110.  
  2111.  
  2112.  
  2113. //-----------------------------------------------------------------------------
  2114. // Name: StaticDirectPlayVoiceClientMessageHandler
  2115. // Desc: Static callback helper to call into CMyApplication class
  2116. //-----------------------------------------------------------------------------
  2117. HRESULT WINAPI CMyApplication::StaticDirectPlayVoiceClientMessageHandler( PVOID pvUserContext, 
  2118.                                                                   DWORD dwMessageId, 
  2119.                                                                   PVOID pMsgBuffer )
  2120. {
  2121.     if( g_pApp )
  2122.         return g_pApp->DirectPlayVoiceClientMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  2123.     return S_OK;
  2124. }
  2125.  
  2126.  
  2127.  
  2128.  
  2129. //-----------------------------------------------------------------------------
  2130. // Name: DirectPlayVoiceClientMessageHandler()
  2131. // Desc: The callback for DirectPlayVoice client messages.  
  2132. //       This handles client messages and updates the UI the whenever a client 
  2133. //       starts or stops talking.  
  2134. //-----------------------------------------------------------------------------
  2135. HRESULT CMyApplication::DirectPlayVoiceClientMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  2136.                                                                 LPVOID lpMessage )
  2137. {
  2138.     // Try not to stay in this message handler for too long, otherwise
  2139.     // there will be a backlog of data.  The best solution is to 
  2140.     // queue data as it comes in, and then handle it on other threads.
  2141.     
  2142.     // This function is called by the DirectPlay message handler pool of 
  2143.     // threads, so be care of thread synchronization problems with shared memory
  2144.  
  2145.     HRESULT hr;
  2146.     HWND hDlg = (HWND) lpvUserContext;
  2147.  
  2148.     switch( dwMessageType )
  2149.     {
  2150.         case DVMSGID_CREATEVOICEPLAYER:
  2151.         {
  2152.             DVMSG_CREATEVOICEPLAYER* pCreateVoicePlayerMsg = (DVMSG_CREATEVOICEPLAYER*) lpMessage;
  2153.             APP_PLAYER_INFO* pPlayerInfo = NULL;
  2154.  
  2155.             // Enter player critical section before accessing player's state data 
  2156.             // otherwise the main thread or other DirectPlay threads may access the data
  2157.             // while this thread is changing it.
  2158.             PLAYER_LOCK(); 
  2159.  
  2160.             // Get the player context associated with this DPNID
  2161.             hr = m_pDP->GetPlayerContext( pCreateVoicePlayerMsg->dvidPlayer, 
  2162.                                           (LPVOID* const) &pPlayerInfo, 0);
  2163.  
  2164.             if( FAILED(hr) || pPlayerInfo == NULL )
  2165.             {
  2166.                 // The player who sent this may have gone away before this 
  2167.                 // message was handled, so just ignore it
  2168.                 PLAYER_UNLOCK();
  2169.                 break;
  2170.             }
  2171.  
  2172.             // Addref player struct, so it can used freely by the voice layer
  2173.             PLAYER_ADDREF( pPlayerInfo ); 
  2174.  
  2175.             pPlayerInfo->bHalfDuplex = ((pCreateVoicePlayerMsg->dwFlags & DVPLAYERCAPS_HALFDUPLEX) != 0);
  2176.  
  2177.             PLAYER_UNLOCK(); // leave player context CS
  2178.  
  2179.             // Set voice context value
  2180.             pCreateVoicePlayerMsg->pvPlayerContext = pPlayerInfo;
  2181.  
  2182.             // We're leaving the extra reference, so the voice layer will 
  2183.             // own that reference
  2184.             break;
  2185.         }
  2186.  
  2187.         case DVMSGID_DELETEVOICEPLAYER:
  2188.         {
  2189.             DVMSG_DELETEVOICEPLAYER* pMsg = (DVMSG_DELETEVOICEPLAYER*) lpMessage;
  2190.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  2191.  
  2192.             // Release our extra reference on the player info that we have for the voice
  2193.             // context value.  
  2194.             PLAYER_LOCK();
  2195.             PLAYER_RELEASE( pPlayerInfo );  
  2196.             PLAYER_UNLOCK();
  2197.             break;
  2198.         }            
  2199.  
  2200.         case DVMSGID_RECORDSTART:             
  2201.         { 
  2202.             DVMSG_RECORDSTART* pMsg = (DVMSG_RECORDSTART*) lpMessage;
  2203.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext;
  2204.  
  2205.             PLAYER_LOCK();
  2206.             if( pPlayerInfo )
  2207.                 pPlayerInfo->bTalking = TRUE;   
  2208.             PLAYER_UNLOCK();
  2209.             break;
  2210.         }
  2211.  
  2212.         case DVMSGID_RECORDSTOP:             
  2213.         {
  2214.             DVMSG_RECORDSTOP* pMsg = (DVMSG_RECORDSTOP*) lpMessage;
  2215.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext;
  2216.  
  2217.             PLAYER_LOCK();
  2218.             if( pPlayerInfo )
  2219.                 pPlayerInfo->bTalking = FALSE;  
  2220.             PLAYER_UNLOCK();
  2221.             break;
  2222.         }
  2223.  
  2224.         case DVMSGID_PLAYERVOICESTART:
  2225.         {
  2226.             DVMSG_PLAYERVOICESTART* pMsg = (DVMSG_PLAYERVOICESTART*) lpMessage;
  2227.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  2228.  
  2229.             PLAYER_LOCK();
  2230.             if( pPlayerInfo )
  2231.                 pPlayerInfo->bTalking = TRUE;   
  2232.             PLAYER_UNLOCK();
  2233.             break;
  2234.         }
  2235.  
  2236.         case DVMSGID_PLAYERVOICESTOP:
  2237.         {
  2238.             DVMSG_PLAYERVOICESTOP* pMsg = (DVMSG_PLAYERVOICESTOP*) lpMessage;
  2239.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  2240.  
  2241.             PLAYER_LOCK();
  2242.             if( pPlayerInfo )
  2243.                 pPlayerInfo->bTalking = FALSE;  
  2244.             PLAYER_UNLOCK();
  2245.             break;
  2246.         }
  2247.     }
  2248.  
  2249.     return S_OK;
  2250. }
  2251.  
  2252.  
  2253.  
  2254.  
  2255. $$ENDIF
  2256. //-----------------------------------------------------------------------------
  2257. // Name: Create()
  2258. // Desc: Creates the window
  2259. //-----------------------------------------------------------------------------
  2260. HRESULT CMyApplication::Create( HINSTANCE hInstance )
  2261. {
  2262.     // Register the window class
  2263.     WNDCLASS wndClass = { CS_DBLCLKS, StaticMsgProc, 0, 0, hInstance, NULL,
  2264.                           LoadCursor( NULL, IDC_ARROW ), 
  2265.                           (HBRUSH)GetSysColorBrush( COLOR_WINDOW ),
  2266.                           NULL, _T("$$root$$ Class") };
  2267.     RegisterClass( &wndClass );
  2268.  
  2269.     // Create our main window
  2270.     HMENU hMenu = LoadMenu( NULL, MAKEINTRESOURCE(IDR_MENU) );
  2271.     m_hWnd = CreateWindowEx( 0, _T("$$root$$ Class"), m_strWindowTitle,
  2272.                                 WS_OVERLAPPEDWINDOW|WS_VISIBLE,
  2273.                                 CW_USEDEFAULT, CW_USEDEFAULT, 
  2274.                                 m_dwCreationWidth, m_dwCreationHeight, 
  2275.                                 NULL, hMenu, hInstance, NULL );
  2276.     if( NULL == m_hWnd )
  2277.         return E_FAIL;
  2278.     UpdateWindow( m_hWnd );
  2279.  
  2280.     // Initialize the application timer
  2281.     DXUtil_Timer( TIMER_START );
  2282.  
  2283.     // Initialize the app's custom scene stuff
  2284.     OneTimeSceneInit();
  2285.  
  2286.     return S_OK;
  2287. }
  2288.  
  2289.  
  2290.  
  2291.  
  2292. //-----------------------------------------------------------------------------
  2293. // Name: Run()
  2294. // Desc: Handles the message loop and calls FrameMove() and Render() when
  2295. //       idle.
  2296. //-----------------------------------------------------------------------------
  2297. INT CMyApplication::Run()
  2298. {
  2299.     MSG msg;
  2300.     HACCEL hAccel = LoadAccelerators( g_hInst, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
  2301.  
  2302.     // Message loop to run the app
  2303.     while( TRUE )
  2304.     {
  2305.         if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
  2306.         {
  2307.             if( FALSE == GetMessage( &msg, NULL, 0, 0 ) )
  2308.                 break;
  2309.  
  2310.             if( 0 == TranslateAccelerator( m_hWnd, hAccel, &msg ) )
  2311.             {
  2312.                 TranslateMessage( &msg );
  2313.                 DispatchMessage( &msg );
  2314.             }
  2315.         }
  2316.         else
  2317.         {
  2318.             // Update the time variables
  2319.             m_fTime        = DXUtil_Timer( TIMER_GETAPPTIME );
  2320.             m_fElapsedTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
  2321.  
  2322.             // This app uses idle time processing for the game loop
  2323.             if( FAILED( FrameMove() ) )
  2324.                 SendMessage( m_hWnd, WM_DESTROY, 0, 0 );
  2325.             if( FAILED( Render() ) ) 
  2326.                 SendMessage( m_hWnd, WM_DESTROY, 0, 0 );
  2327.  
  2328.             Sleep( 20 );
  2329.         }
  2330.     }
  2331.  
  2332.     FinalCleanup();
  2333.  
  2334.     return (INT)msg.wParam;
  2335. }
  2336.  
  2337.  
  2338.  
  2339.  
  2340.